agora inbox for [email protected]  
help / color / mirror / Atom feed
[PATCH v11 3/7] Row pattern recognition patch (planner).
121+ messages / 2 participants
[nested] [flat]

* [PATCH v11 3/7] Row pattern recognition patch (planner).
@ 2023-11-08 06:57 Tatsuo Ishii <[email protected]>
  0 siblings, 0 replies; 121+ messages in thread

From: Tatsuo Ishii @ 2023-11-08 06:57 UTC (permalink / raw)

---
 src/backend/optimizer/plan/createplan.c   | 23 ++++++++++++++-----
 src/backend/optimizer/plan/setrefs.c      | 27 ++++++++++++++++++++++-
 src/backend/optimizer/prep/prepjointree.c |  4 ++++
 src/include/nodes/plannodes.h             | 16 ++++++++++++++
 4 files changed, 64 insertions(+), 6 deletions(-)

diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 34ca6d4ac2..469fcd156b 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -286,9 +286,10 @@ static WindowAgg *make_windowagg(List *tlist, Index winref,
 								 int ordNumCols, AttrNumber *ordColIdx, Oid *ordOperators, Oid *ordCollations,
 								 int frameOptions, Node *startOffset, Node *endOffset,
 								 Oid startInRangeFunc, Oid endInRangeFunc,
-								 Oid inRangeColl, bool inRangeAsc, bool inRangeNullsFirst,
-								 List *runCondition, List *qual, bool topWindow,
-								 Plan *lefttree);
+								 Oid inRangeColl, bool inRangeAsc, bool inRangeNullsFirst, List *runCondition,
+								 RPSkipTo rpSkipTo, List *patternVariable, List *patternRegexp, List *defineClause,
+								 List *defineInitial,
+								 List *qual, bool topWindow, Plan *lefttree);
 static Group *make_group(List *tlist, List *qual, int numGroupCols,
 						 AttrNumber *grpColIdx, Oid *grpOperators, Oid *grpCollations,
 						 Plan *lefttree);
@@ -2698,6 +2699,11 @@ create_windowagg_plan(PlannerInfo *root, WindowAggPath *best_path)
 						  wc->inRangeAsc,
 						  wc->inRangeNullsFirst,
 						  wc->runCondition,
+						  wc->rpSkipTo,
+						  wc->patternVariable,
+						  wc->patternRegexp,
+						  wc->defineClause,
+						  wc->defineInitial,
 						  best_path->qual,
 						  best_path->topwindow,
 						  subplan);
@@ -6601,8 +6607,10 @@ make_windowagg(List *tlist, Index winref,
 			   int ordNumCols, AttrNumber *ordColIdx, Oid *ordOperators, Oid *ordCollations,
 			   int frameOptions, Node *startOffset, Node *endOffset,
 			   Oid startInRangeFunc, Oid endInRangeFunc,
-			   Oid inRangeColl, bool inRangeAsc, bool inRangeNullsFirst,
-			   List *runCondition, List *qual, bool topWindow, Plan *lefttree)
+			   Oid inRangeColl, bool inRangeAsc, bool inRangeNullsFirst, List *runCondition,
+			   RPSkipTo rpSkipTo, List *patternVariable, List *patternRegexp, List *defineClause,
+			   List *defineInitial,
+			   List *qual, bool topWindow, Plan *lefttree)
 {
 	WindowAgg  *node = makeNode(WindowAgg);
 	Plan	   *plan = &node->plan;
@@ -6628,6 +6636,11 @@ make_windowagg(List *tlist, Index winref,
 	node->inRangeAsc = inRangeAsc;
 	node->inRangeNullsFirst = inRangeNullsFirst;
 	node->topWindow = topWindow;
+	node->rpSkipTo = rpSkipTo,
+	node->patternVariable = patternVariable;
+	node->patternRegexp = patternRegexp;
+	node->defineClause = defineClause;
+	node->defineInitial = defineInitial;
 
 	plan->targetlist = tlist;
 	plan->lefttree = lefttree;
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index fc3709510d..bda99d1c51 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -211,7 +211,6 @@ static List *set_windowagg_runcondition_references(PlannerInfo *root,
 												   List *runcondition,
 												   Plan *plan);
 
-
 /*****************************************************************************
  *
  *		SUBPLAN REFERENCES
@@ -2456,6 +2455,32 @@ set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
 					   NRM_EQUAL,
 					   NUM_EXEC_QUAL(plan));
 
+	/*
+	 *	Modifies an expression tree in each DEFINE clause so that all Var
+	 *	nodes's varno refers to OUTER_VAR.
+	 */
+	if (IsA(plan, WindowAgg))
+	{
+		WindowAgg  *wplan = (WindowAgg *) plan;
+
+		if (wplan->defineClause != NIL)
+		{
+			foreach(l, wplan->defineClause)
+			{
+				TargetEntry *tle = (TargetEntry *) lfirst(l);
+
+				tle->expr = (Expr *)
+					fix_upper_expr(root,
+								   (Node *) tle->expr,
+								   subplan_itlist,
+								   OUTER_VAR,
+								   rtoffset,
+								   NRM_EQUAL,
+								   NUM_EXEC_QUAL(plan));
+			}
+		}
+	}
+
 	pfree(subplan_itlist);
 }
 
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index 73ff40721c..378644b2c4 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -2129,6 +2129,10 @@ perform_pullup_replace_vars(PlannerInfo *root,
 		if (wc->runCondition != NIL)
 			wc->runCondition = (List *)
 				pullup_replace_vars((Node *) wc->runCondition, rvcontext);
+
+		if (wc->defineClause != NIL)
+			wc->defineClause = (List *)
+				pullup_replace_vars((Node *) wc->defineClause, rvcontext);
 	}
 	if (parse->onConflict)
 	{
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index d40af8e59f..827b86fea9 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -20,6 +20,7 @@
 #include "lib/stringinfo.h"
 #include "nodes/bitmapset.h"
 #include "nodes/lockoptions.h"
+#include "nodes/parsenodes.h"
 #include "nodes/primnodes.h"
 
 
@@ -1096,6 +1097,21 @@ typedef struct WindowAgg
 	/* nulls sort first for in_range tests? */
 	bool		inRangeNullsFirst;
 
+	/* Row Pattern Recognition AFTER MACH SKIP clause */
+	RPSkipTo	rpSkipTo;		/* Row Pattern Skip To type */
+
+	/* Row Pattern PATTERN variable name (list of String) */
+	List		*patternVariable;
+
+	/* Row Pattern RPATTERN regular expression quantifier ('+' or ''. list of String) */
+	List		*patternRegexp;
+
+	/* Row Pattern DEFINE clause (list of TargetEntry) */
+	List	   *defineClause;
+
+	/* Row Pattern DEFINE variable initial names (list of String) */
+	List		*defineInitial;
+
 	/*
 	 * false for all apart from the WindowAgg that's closest to the root of
 	 * the plan
-- 
2.25.1


----Next_Part(Wed_Nov__8_16_37_05_2023_872)--
Content-Type: Text/X-Patch; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="v11-0004-Row-pattern-recognition-patch-executor.patch"



^ permalink  raw  reply  [nested|flat] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ 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; 121+ 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] 121+ messages in thread


end of thread, other threads:[~2026-06-30 15:29 UTC | newest]

Thread overview: 121+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2023-11-08 06:57 [PATCH v11 3/7] Row pattern recognition patch (planner). Tatsuo Ishii <[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