[PATCH v2 2/2] fixups
Álvaro Herrera <alvherre@kurilemu.de>
From: Álvaro Herrera <alvherre@kurilemu.de>
To:
Date: 2026-07-07T16:35:28Z
Lists: pgsql-hackers
---
src/backend/commands/repack.c | 54 ++++++++++++++++++++++-------------
1 file changed, 34 insertions(+), 20 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 2879c8af574..fcc401ccdb9 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -2152,6 +2152,10 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
/*
* For USING INDEX, scan pg_index to find those with indisclustered.
+ *
+ * Note we don't obtain lock of any kind on the index, which means the
+ * index or its owning table could be gone or change at any point. We
+ * have to be extra careful when examining catalog state for them.
*/
catalog = table_open(IndexRelationId, AccessShareLock);
ScanKeyInit(&entry,
@@ -2169,7 +2173,7 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
index = (Form_pg_index) GETSTRUCT(tuple);
- classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(index->indrelid));
+ classtup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(index->indrelid));
if (!HeapTupleIsValid(classtup))
continue;
classForm = (Form_pg_class) GETSTRUCT(classtup);
@@ -2178,11 +2182,11 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt)
if (classForm->relpersistence == RELPERSISTENCE_TEMP &&
!isTempOrTempToastNamespace(classForm->relnamespace))
{
- ReleaseSysCache(classtup);
+ heap_freetuple(classtup);
continue;
}
- ReleaseSysCache(classtup);
+ heap_freetuple(classtup);
/* noisily skip rels which the user can't process */
if (!repack_is_permitted_for_relation(cmd, index->indrelid,
@@ -2274,7 +2278,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
if (get_rel_relkind(child_oid) != RELKIND_INDEX)
continue;
- table_oid = IndexGetRelation(child_oid, false);
+ table_oid = IndexGetRelation(child_oid, true);
+ if (!OidIsValid(table_oid))
+ continue;
index_oid = child_oid;
}
else
@@ -2309,33 +2315,41 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid,
/*
- * Return whether userid has privileges to REPACK relid. If not, this
- * function emits a WARNING.
+ * Return whether userid has privileges to execute REPACK on relid.
+ *
+ * Caller may not have a lock on the relation, so it could have been
+ * dropped concurrently. In that case, silently return false.
+ *
+ * If the relation does exist but the user doesn't have the required
+ * privs, emit a WARNING and return false. Otherwise, return true.
*/
static bool
repack_is_permitted_for_relation(RepackCommand cmd, Oid relid, Oid userid)
{
bool is_missing = false;
+ AclResult result;
+ char *relname;
Assert(cmd == REPACK_COMMAND_CLUSTER || cmd == REPACK_COMMAND_REPACK);
- if (pg_class_aclcheck_ext(relid, userid, ACL_MAINTAIN, &is_missing) == ACLCHECK_OK)
+ result = pg_class_aclcheck_ext(relid, userid, ACL_MAINTAIN, &is_missing);
+ if (is_missing)
+ return false;
+
+ if (result == ACLCHECK_OK)
return true;
- /* Report a warning if the relation still exists. */
- if (!is_missing)
+ /*
+ * The relation can also be dropped after we tested its ACL and before we
+ * read its relname, so be careful.
+ */
+ relname = get_rel_name(relid);
+ if (relname != NULL)
{
- char *relname;
-
- relname = get_rel_name(relid);
- if (relname != NULL)
- {
- ereport(WARNING,
- errmsg("permission denied to execute %s on \"%s\", skipping it",
- RepackCommandAsString(cmd), relname));
-
- pfree(relname);
- }
+ ereport(WARNING,
+ errmsg("permission denied to execute %s on \"%s\", skipping it",
+ RepackCommandAsString(cmd), relname));
+ pfree(relname);
}
return false;
--
2.47.3
--op6mnexl7cn72cto--