agora inbox for [email protected]  
help / color / mirror / Atom feed
[PATCH v25 2/4] Refactor index_concurrently_create_copy() for use with REPACK (CONCURRENTLY).
191+ messages / 2 participants
[nested] [flat]

* [PATCH v25 2/4] Refactor index_concurrently_create_copy() for use with REPACK (CONCURRENTLY).
@ 2025-08-11 13:31  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Antonin Houska @ 2025-08-11 13:31 UTC (permalink / raw)

This patch moves the code to index_create_copy() and adds a "concurrently"
parameter so it can be used by REPACK (CONCURRENTLY).

With the CONCURRENTLY option, REPACK cannot simply swap the heap file and
rebuild its indexes. Instead, it needs to build a separate set of indexes
(including system catalog entries) *before* the actual swap, to reduce the
time AccessExclusiveLock needs to be held for.
---
 src/backend/catalog/index.c | 36 ++++++++++++++++++++++++++++--------
 src/include/catalog/index.h |  3 +++
 2 files changed, 31 insertions(+), 8 deletions(-)

diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 08d4b8e44d7..2b33bf04883 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1290,15 +1290,31 @@ index_create(Relation heapRelation,
 /*
  * index_concurrently_create_copy
  *
- * Create concurrently an index based on the definition of the one provided by
- * caller.  The index is inserted into catalogs and needs to be built later
- * on.  This is called during concurrent reindex processing.
- *
- * "tablespaceOid" is the tablespace to use for this index.
+ * Variant of index_create_copy(), called during concurrent reindex
+ * processing.
  */
 Oid
 index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
 							   Oid tablespaceOid, const char *newName)
+{
+	return index_create_copy(heapRelation, oldIndexId, tablespaceOid, newName,
+							 true);
+}
+
+/*
+ * index_create_copy
+ *
+ * Create an index based on the definition of the one provided by caller.  The
+ * index is inserted into catalogs and needs to be built later on.
+ *
+ * "tablespaceOid" is the tablespace to use for this index.
+ *
+ * The actual implementation of index_concurrently_create_copy(), reusable for
+ * other purposes.
+ */
+Oid
+index_create_copy(Relation heapRelation, Oid oldIndexId, Oid tablespaceOid,
+				  const char *newName, bool concurrently)
 {
 	Relation	indexRelation;
 	IndexInfo  *oldInfo,
@@ -1317,6 +1333,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
 	List	   *indexColNames = NIL;
 	List	   *indexExprs = NIL;
 	List	   *indexPreds = NIL;
+	int			flags = 0;
 
 	indexRelation = index_open(oldIndexId, RowExclusiveLock);
 
@@ -1325,9 +1342,9 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
 
 	/*
 	 * Concurrent build of an index with exclusion constraints is not
-	 * supported.
+	 * supported. If !concurrently, ii_ExclusinOps is currently not needed.
 	 */
-	if (oldInfo->ii_ExclusionOps != NULL)
+	if (oldInfo->ii_ExclusionOps != NULL && concurrently)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("concurrent index creation for exclusion constraints is not supported")));
@@ -1435,6 +1452,9 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
 		stattargets[i].isnull = isnull;
 	}
 
+	if (concurrently)
+		flags = INDEX_CREATE_SKIP_BUILD | INDEX_CREATE_CONCURRENT;
+
 	/*
 	 * Now create the new index.
 	 *
@@ -1458,7 +1478,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
 							  indcoloptions->values,
 							  stattargets,
 							  reloptionsDatum,
-							  INDEX_CREATE_SKIP_BUILD | INDEX_CREATE_CONCURRENT,
+							  flags,
 							  0,
 							  true, /* allow table to be a system catalog? */
 							  false,	/* is_internal? */
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index dda95e54903..4bf909078d8 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -99,6 +99,9 @@ extern Oid	index_concurrently_create_copy(Relation heapRelation,
 										   Oid oldIndexId,
 										   Oid tablespaceOid,
 										   const char *newName);
+extern Oid	index_create_copy(Relation heapRelation, Oid oldIndexId,
+							  Oid tablespaceOid, const char *newName,
+							  bool concurrently);
 
 extern void index_concurrently_build(Oid heapRelationId,
 									 Oid indexRelationId);
-- 
2.47.3


--ecl2euvoqutt27wj
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
	filename="v25-0003-Move-conversion-of-a-historic-to-MVCC-snapshot-t.patch"



^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread

* [PATCH v8 1/1] handle concurrent drop in database-wide vacuum
@ 2026-06-30 15:29  Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 191+ messages in thread

From: Nathan Bossart @ 2026-06-30 15:29 UTC (permalink / raw)

---
 src/backend/commands/analyze.c |  3 ++-
 src/backend/commands/vacuum.c  | 23 ++++++++++++++++++-----
 src/include/commands/vacuum.h  |  2 +-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757c..c28b9dae983 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -157,7 +157,8 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 */
 	if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
 										  onerel->rd_rel,
-										  params->options & ~VACOPT_VACUUM))
+										  params->options & ~VACOPT_VACUUM,
+										  false))
 	{
 		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a4abb29cf64..a402d2330f0 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -718,9 +718,10 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
  */
 bool
 vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-								 uint32 options)
+								 uint32 options, bool missing_ok)
 {
 	char	   *relname;
+	bool		is_missing = false;
 
 	Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
@@ -733,9 +734,20 @@ 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,
+							  missing_ok ? &is_missing : NULL) == ACLCHECK_OK)
 		return true;
 
+	/*
+	 * If the relation was concurrently dropped, nothing to do.  Note that
+	 * this is only reachable when the caller specified missing_ok.
+	 */
+	if (is_missing)
+	{
+		Assert(missing_ok);
+		return false;
+	}
+
 	relname = NameStr(reltuple->relname);
 
 	if ((options & VACOPT_VACUUM) != 0)
@@ -956,7 +968,7 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
 		 * Make a returnable VacuumRelation for this rel if the user has the
 		 * required privileges.
 		 */
-		if (vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (vacuum_is_permitted_for_relation(relid, classForm, options, false))
 		{
 			oldcontext = MemoryContextSwitchTo(vac_context);
 			vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1069,7 +1081,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
 			continue;
 
 		/* check permissions of relation */
-		if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+		if (!vacuum_is_permitted_for_relation(relid, classForm, options, true))
 			continue;
 
 		/*
@@ -2115,7 +2127,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 */
 	if (!vacuum_is_permitted_for_relation(priv_relid,
 										  rel->rd_rel,
-										  params.options & ~VACOPT_ANALYZE))
+										  params.options & ~VACOPT_ANALYZE,
+										  false))
 	{
 		relation_close(rel, lmode);
 		PopActiveSnapshot();
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36d..e62f23748dc 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -389,7 +389,7 @@ extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(bool is_analyze);
 extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-											 uint32 options);
+											 uint32 options, bool missing_ok);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
 									 uint32 options, bool verbose,
 									 LOCKMODE lmode);
-- 
2.50.1 (Apple Git-155)


--dDwC+h/KQNl/aRwi--





^ permalink  raw  reply  [nested|flat] 191+ messages in thread


end of thread, other threads:[~2026-06-30 15:29 UTC | newest]

Thread overview: 191+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2025-08-11 13:31 [PATCH v25 2/4] Refactor index_concurrently_create_copy() for use with REPACK (CONCURRENTLY). Antonin Houska <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>
2026-06-30 15:29 [PATCH v8 1/1] handle concurrent drop in database-wide vacuum Nathan Bossart <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox