Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wiC7K-0003v1-19 for pgsql-hackers@arkaria.postgresql.org; Fri, 10 Jul 2026 14:22:15 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wiC7I-000eH5-1K for pgsql-hackers@arkaria.postgresql.org; Fri, 10 Jul 2026 14:22:13 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wiC7H-000eGq-1v for pgsql-hackers@lists.postgresql.org; Fri, 10 Jul 2026 14:22:12 +0000 Received: from fout-b5-smtp.messagingengine.com ([202.12.124.148]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1wiC7G-000000002k0-0Wu6 for pgsql-hackers@lists.postgresql.org; Fri, 10 Jul 2026 14:22:11 +0000 Received: from phl-compute-05.internal (phl-compute-05.internal [10.202.2.45]) by mailfout.stl.internal (Postfix) with ESMTP id 739311D000AE; Fri, 10 Jul 2026 10:22:09 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-05.internal (MEProxy); Fri, 10 Jul 2026 10:22:09 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kurilemu.de; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :reply-to:subject:subject:to:to; s=fm3; t=1783693329; x= 1783779729; bh=a37lLsg9AYDB2EtrhPkSyUna8lkIaSEDHLXo/9ZPcwg=; b=O 47kV/jSAfcnDpGoRuMEFcH6uImEhroFYKkCLFnQvNEWf0+PaCmNqPWvuFEHAvE5d Jb1VDsvo5MADbgqu9e+jKu/zI/CFhCBbdw7oCHaKMnEdlwiizGXHA1CbWLBizFGT 1UdzprLxSG6KA6O3VoRAYm2kuWBMv8saBnY29L5KAP4xZWqrdEY/SN8ryMHr8v0k SztkHfbImFa7fORNFvbSXK5N8PRp4Mlp8CNbbwaEc5Mk8TnxEZUdg+vg6V+QH0GZ ztwROdAUSBAUyH3PY0qJhWCO9lJu7P/N2048tGNssb5+MTVramemkccgc8iTROq6 McQcJwugDkt4act6Mz3aQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm2; t=1783693329; x=1783779729; bh=a 37lLsg9AYDB2EtrhPkSyUna8lkIaSEDHLXo/9ZPcwg=; b=gWHfSunliDuUFwoc4 Ve8h/X0P1O5G70PmKYor2MKyrxfLPVwyZU2ykchHi1h0YQoSKTd5pT1etFhGa21o 7yyLXIYw5HUlINVPWEYBpkn6Bmd1ZFnNe7avRj5hGleQ6EfAgpQYxIx/6fSpqZWz CYqEQkukXsX6cV+dgBXe6lh2CtNzJUBItM4tmpO4ZZUWfzEykJPh/zV1WKHLsNWm MXJVD9xQLpakDlEqzMSWRo5VOuPNOwFxVg00S7tBYYg/ILc40ponZNiRbQhcBCrC uoyQUGqm+weZUtr/yDFcny/Nc1aIKmfqXbWN/DCOBDrVz1ci0hT9ZJfrs/Dz9q27 beZLQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTFmyfiRi1A+SGr+UlBMBzdYkaAlHI4eZVZulb/zFWViVj2xXKaW/51TIJRe7oskY2 koZCXChHulnY1U2UzigWkKrF9vbfPH20DQ09xxXBtRAI8A7KIHmLbIcH7O+6mSs05Nsk5X G6oQgiTVIj3UX5fIIUGpp5e2MIbD+CY9fJoxA8E5F1ya972l/oJo0MEtsdgvrHGLvGYT6S OnY0nANWq+2m12W/BJoZK0LO6/viJbCyLDM+VHRuL4IbSA2vkf6bZ7JNU2lR622dczLZ9Y Chxu/Nxh1pyxcowG8O2oN/8QMFJzJLRHuxvsOHYdTzVeeOW6klT3lg/gIVoUrep5v/CaQy z3qIpE/jwwL60GMPMCZl2jviQetuKQrxfXwYKoK5szwClCAOdrpcn0HuYDBprRgtcS3NbR cPVKPDBfhc71R266FEl1Fa0xemlxOQPY3go46XpxZgA2b0XjovIHxsldM8NaVwaPhNiH59 3ACZpUjyUyubxCRcVQgYWIumdbz6TSGW9lbs6YL8Xtz6aOTlLTd5ZsyXANhl2bHP93MIG0 k9cdAovpuiSU5c4RtcsLZKGaZeFs1IrHXnQcEHAoZnfVdpU7WgrO/sTypvZ+Mor+lzkEEI 3BB3CvoBXFOqxf+ZQeKm2kXJTbd+2VAxuuglhG6AxVer0fSHKzxmd8cKDHuQ X-ME-Proxy: Feedback-ID: ie3de48e3:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 10 Jul 2026 10:22:08 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kurilemu.de; s=schmee; t=1783693324; bh=7C6WsJI1E2Sqidz3xX5eIgXRyBKjXuZFyboB1x2Pmes=; h=Date:From:To:Cc:Subject:In-Reply-To:From; b=wodEtj2/41paQdSPuD1naS9fLW13K0Va+jQajLOl7WeJwf0Z1n63IJFekERUkf+KP 8MSlJX0RpgORNnNTq/HvjKVLmf0pu/HtIHG0QUq7ia+h0LKpW5gBaA9qkWNzgcG+BC FGLBRgOwq9JQAUYbN5nqFbWspbYzqOm9kRRMx3WXtiOGprIOuVhr9cq8axFHvwBEfV weMQXfpl+A7BHfkmcOapqSkmLLW7BLAqJ2WKCmybGZcFrbe4Oq1aZVACJcOo6SyI3q O9hMIOEI8Zy+PL9ajxvUxzlytApB/ZHuiOUfAZVC4gqIlZiDjQTMOLeHG874lhmN7z FLzbcqU4CbSxA== Received: by ida.kurilemu.internal (Postfix, from userid 1000) id 7302EB0000B; Fri, 10 Jul 2026 16:22:04 +0200 (CEST) Date: Fri, 10 Jul 2026 16:22:04 +0200 From: =?utf-8?Q?=C3=81lvaro?= Herrera To: cca5507 Cc: pgsql-hackers Subject: Re: Do not lock tables in get_tables_to_repack Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="f4uihmgjmvhgvze3" Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --f4uihmgjmvhgvze3 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit On 2026-Jul-08, cca5507 wrote: > - classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(index->indrelid)); > + classtup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(index->indrelid)); > > Do we really need to copy it? We hold a refcount on it so it won't be freed > until we release it. Otherwise LGTM. Yeah, I guess it doesn't matter. I have removed the copy and updated some comments. I also realized that there are some places where we weren't dealing correctly with the possibility that the relation goes away, or is replaced with something different, so I added that too. While looking at it I also realized that get_tables_to_repack_partitioned is likewise not careful enough about it: we do IndexGetRelation(, false) which fails hard if the pg_index tuple cannot be found, which is the wrong thing to do. At the same time, it's annoying that half of the code that clearly belongs in that routine is actually in ExecRepack(). I moved that to where it rightfully belongs. (The only somewhat annoying thing is that we have to NULL-out the Relation pointer after returning; but that's not *too* bad IMO.) Any opinions on this? -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/ "No me acuerdo, pero no es cierto. No es cierto, y si fuera cierto, no me acuerdo." (Augusto Pinochet a una corte de justicia) --f4uihmgjmvhgvze3 Content-Type: text/x-diff; charset=utf-8 Content-Disposition: attachment; filename=0001-change-get_tables_to_repack_partitioned.patch From e192b820d83c6c8a99e901178ec891a4db59da07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Herrera?= Date: Thu, 9 Jul 2026 16:55:12 +0200 Subject: [PATCH] change get_tables_to_repack_partitioned --- src/backend/commands/repack.c | 127 +++++++++++++++++----------------- 1 file changed, 65 insertions(+), 62 deletions(-) diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c index 02883fe34a4..b3589ceff51 100644 --- a/src/backend/commands/repack.c +++ b/src/backend/commands/repack.c @@ -169,8 +169,8 @@ static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldInde MultiXactId *pCutoffMulti); static List *get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt); -static List *get_tables_to_repack_partitioned(RepackCommand cmd, - Oid relid, bool rel_is_index, +static List *get_tables_to_repack_partitioned(RepackStmt *stmt, + Relation rel, MemoryContext permcxt); static bool repack_is_permitted_for_relation(RepackCommand cmd, Oid relid, Oid userid); @@ -387,58 +387,8 @@ ExecRepack(ParseState *pstate, RepackStmt *stmt, bool isTopLevel) } else { - Oid relid; - bool rel_is_index; - - Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE); - - /* - * If USING INDEX was specified, resolve the index name now and pass - * it down. - */ - if (stmt->usingindex) - { - /* - * If no index name was specified when repacking a partitioned - * table, punt for now. Maybe we can improve this later. - */ - if (!stmt->indexname) - { - if (stmt->command == REPACK_COMMAND_CLUSTER) - ereport(ERROR, - errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("there is no previously clustered index for table \"%s\"", - RelationGetRelationName(rel))); - else - ereport(ERROR, - errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - /*- translator: first %s is name of a SQL command, eg. REPACK */ - errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name", - RepackCommandAsString(stmt->command), - RelationGetRelationName(rel))); - } - - relid = determine_clustered_index(rel, stmt->usingindex, - stmt->indexname); - if (!OidIsValid(relid)) - elog(ERROR, "unable to determine index to cluster on"); - check_index_is_clusterable(rel, relid, AccessExclusiveLock); - - rel_is_index = true; - } - else - { - relid = RelationGetRelid(rel); - rel_is_index = false; - } - - rtcs = get_tables_to_repack_partitioned(stmt->command, - relid, rel_is_index, - repack_context); - - /* close parent relation, releasing lock on it */ - table_close(rel, AccessExclusiveLock); - rel = NULL; + rtcs = get_tables_to_repack_partitioned(stmt, rel, repack_context); + rel = NULL; /* clobber no longer valid pointer */ } /* Commit to get out of starting transaction */ @@ -2255,19 +2205,66 @@ get_tables_to_repack(RepackCommand cmd, bool usingindex, MemoryContext permcxt) } /* - * Given a partitioned table or its index, return a list of RelToCluster for - * all the leaf child tables/indexes. + * Resolve a partitioned table named as target of REPACK to the list of + * its partitions, and return it as a list of RelToCluster. * - * 'rel_is_index' tells whether 'relid' is that of an index (true) or of the - * owning relation. + * The partitioned table in question was already opened and locked by caller + * and is given as argument; it is closed and unlocked here before return. */ static List * -get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid, - bool rel_is_index, MemoryContext permcxt) +get_tables_to_repack_partitioned(RepackStmt *stmt, Relation rel, + MemoryContext permcxt) { + Oid relid; + bool rel_is_index; List *inhoids; List *rtcs = NIL; + Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE); + Assert(CheckRelationLockedByMe(rel, AccessExclusiveLock, false)); + + /* + * We find the list of tables by looking for inheritors. If USING INDEX + * was given, look for inheritors of that index, whose name we resolve now. + * + * Otherwise we look for inheritors of the table itself. + */ + if (stmt->usingindex) + { + /* + * If no index name was specified when repacking a partitioned + * table, punt for now. Maybe we can improve this later. + */ + if (!stmt->indexname) + { + if (stmt->command == REPACK_COMMAND_CLUSTER) + ereport(ERROR, + errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("there is no previously clustered index for table \"%s\"", + RelationGetRelationName(rel))); + else + ereport(ERROR, + errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + /*- translator: first %s is name of a SQL command, eg. REPACK */ + errmsg("cannot execute %s on partitioned table \"%s\" USING INDEX with no index name", + RepackCommandAsString(stmt->command), + RelationGetRelationName(rel))); + } + + relid = determine_clustered_index(rel, stmt->usingindex, + stmt->indexname); + if (!OidIsValid(relid)) + elog(ERROR, "unable to determine index to cluster on"); + check_index_is_clusterable(rel, relid, AccessExclusiveLock); + + rel_is_index = true; + } + else + { + relid = RelationGetRelid(rel); + rel_is_index = false; + } + /* * Do not lock the children until they're processed. Note that we do hold * a lock on the parent partitioned table. @@ -2286,7 +2283,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 @@ -2304,7 +2303,8 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid, * leaf partition despite having them on the partitioned table. Skip * if so. */ - if (!repack_is_permitted_for_relation(cmd, table_oid, GetUserId())) + if (!repack_is_permitted_for_relation(stmt->command, table_oid, + GetUserId())) continue; /* Use a permanent memory context for the result list */ @@ -2316,6 +2316,9 @@ get_tables_to_repack_partitioned(RepackCommand cmd, Oid relid, MemoryContextSwitchTo(oldcxt); } + /* close parent relation, releasing lock on it */ + table_close(rel, AccessExclusiveLock); + return rtcs; } -- 2.47.3 --f4uihmgjmvhgvze3--