Thread
-
[PATCH v2 2/2] fixups
Álvaro Herrera <alvherre@kurilemu.de> — 2026-07-07T16:35:28Z
--- 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--