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.94.2) (envelope-from ) id 1t5LrR-005Wtv-V8 for pgsql-hackers@arkaria.postgresql.org; Mon, 28 Oct 2024 09:16:30 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1t5LrQ-0056wk-8G for pgsql-hackers@arkaria.postgresql.org; Mon, 28 Oct 2024 09:16:28 +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.94.2) (envelope-from ) id 1t5LrP-0056wc-HT for pgsql-hackers@lists.postgresql.org; Mon, 28 Oct 2024 09:16:28 +0000 Received: from fout-a1-smtp.messagingengine.com ([103.168.172.144]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1t5LrM-003FSd-Nq for pgsql-hackers@postgresql.org; Mon, 28 Oct 2024 09:16:26 +0000 Received: from phl-compute-01.internal (phl-compute-01.phl.internal [10.202.2.41]) by mailfout.phl.internal (Postfix) with ESMTP id 1747713801CF; Mon, 28 Oct 2024 05:16:23 -0400 (EDT) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-01.internal (MEProxy); Mon, 28 Oct 2024 05:16:23 -0400 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-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1730106983; x= 1730193383; bh=CAy3Ai14We8ns4t46r6g2r05+tYe8NJaw9i4B/LgWTI=; b=h lMbcd1404IPNyyurDtNZNxJRbSWflNd9xDcOcnAP0HR+PmTJb3dXf8gOp6+A4RLE 0aqcypw8P+HN1BvpxvQInIh3mwv/Mipfo0bnD8m8oBLd/HpzUiMP+5+p88OOqb8o zMW+kH879m4UT6DnJBpLGoseP3Ztc+ACkgowhbIAqQHsv+zZA5bBlLmEEozEI1kC HsBlnFDjWFJHl6I9aYShB2N0faMHnoS7Hp3dTg6rKdQ/o1v6GDEHjntQd2qwAwkB 4gOuwpUaRgNuwaBVisJFGnn1HDPCnTF5pEkNSiP5vqeNPJ2/OTZ7Lim1JCrp/72G 6g6F2NKta3tmLZD8D1jDg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrvdejkedgtdduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnh htshculddquddttddmnecujfgurhepfffhvfevuffkgggtugfgjgesmhekreertddtjeen ucfhrhhomheptehlvhgrrhhoucfjvghrrhgvrhgruceorghlvhhhvghrrhgvsegrlhhvhh drnhhoqdhiphdrohhrgheqnecuggftrfgrthhtvghrnhepudelkeekgfdttdettdekgfdu vdeiffelteegjeeihfetheekveeftedtuddvhfeunecuffhomhgrihhnpegvnhhtvghrph hrihhsvggusgdrtghomhenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgr ihhlfhhrohhmpegrlhhvhhgvrhhrvgesrghlvhhhrdhnohdqihhprdhorhhgpdhnsggprh gtphhtthhopeehpdhmohguvgepshhmthhpohhuthdprhgtphhtthhopehjghgurhesuggr lhhisghordgtohhmpdhrtghpthhtohepvgigtghluhhsihhonhesghhmrghilhdrtghomh dprhgtphhtthhopehtnhgurhifrghnghesghhmrghilhdrtghomhdprhgtphhtthhopehg uhhilhhlrghumhgvsehlvghlrghrghgvrdhinhhfohdprhgtphhtthhopehpghhsqhhlqd hhrggtkhgvrhhssehpohhsthhgrhgvshhqlhdrohhrgh X-ME-Proxy: Feedback-ID: ia2694551:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 28 Oct 2024 05:16:22 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alvh.no-ip.org; s=schmee; t=1730106978; bh=Y/2ld2mPVBd4wF+/GsCm2p2/12cmn9+bX57FneJJttM=; h=Date:From:To:Cc:Subject:In-Reply-To:From; b=Nv0HMWROqYIryS1jcBu4buCxCFD02Y9G4aLIZ6IglJa1lc8TbcnBMMJrzzUfP8tnQ hS6KU9BczW6cSvJQa5w3UfeDk4p/1C0TPHOBtEgyKppy7tgFw3inFqaksZYniZsBSS S3PTvsHxzuXHOKSiYnnrpZetMTawHqt5PH9O8vUbin2jF9UBluU4Yju3T8/sj+ulOP meNyXTM3p0kqv00RiUN1e+3wBUxkbiaHHLB1BxXMF/Y3N3V9reYj9B4kzo/ErbZG2N bKItehFrkoS2abMpZoUfMDm9nKCfk+AQtyvfaf2C3aQe8mZsem+Vrff1r/g5gF3ppf AZdYyggUdXVnA== Received: by schmee.alvh.no-ip.org (Postfix, from userid 1000) id 062A891; Mon, 28 Oct 2024 10:16:17 +0100 (CET) Date: Mon, 28 Oct 2024 10:16:17 +0100 From: Alvaro Herrera To: Tender Wang Cc: Alexander Lakhin , Jehan-Guillaume de Rorthais , "pgsql-hackers@postgresql.org" , Guillaume Lelarge Subject: Re: [BUG] Fix DETACH with FK pointing to a partitioned table fails Message-ID: <202410280916.7zm2gv25farn@alvherre.pgsql> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="venjkcsjyivuur74" 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 --venjkcsjyivuur74 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit On 2024-Oct-27, Tender Wang wrote: > BTW, while reviewing the v2 patch, I found the parentConTup in > foreach(cell, fks) block > didn't need it anymore. We can remove the related codes. True. Done so in this v3. I noticed another problem here: we're grabbing the wrong lock type on the referenced rel (AccessShareLock) during detach. (What's more: we release it afterwards, which is the wrong thing to do. We need to keep such locks until end of transaction). I didn't try to construct a case where this would be a problem, but if I change AccessShare to NoLock, the assertion that says we don't hold _any_ lock on that relation fires, which means that we're not taking any locks on those rels before this point. So this lock strength choice is definitely wrong. I changed it to ShareRowExclusive, which is what we're suppose to use when adding a trigger. Another option might be to do find_all_inheritors() ahead of time to grab all the necessary locks, but I didn't try to do that. I also added an assertion in addFkRecurseReferenced to verify that we hold that in all paths, and after this change it doesn't fire anymore with the regression tests. I have still not edited the commit message. -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/ --venjkcsjyivuur74 Content-Type: text/x-diff; charset=utf-8 Content-Disposition: attachment; filename="v3-0001-No-need-to-use-an-attrmap-when-detaching-a-foreig.patch" From 3f18de0a263e507b79b1f1eb9a9a128cd6292779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Herrera?= Date: Sat, 26 Oct 2024 23:44:58 +0200 Subject: [PATCH v3] No need to use an attrmap when detaching a foreign key The reason is that the constraint being created is on the same relation as the constraint that it spawns from. --- src/backend/commands/tablecmds.c | 25 ++++++++--------------- src/test/regress/expected/foreign_key.out | 9 +++++--- src/test/regress/sql/foreign_key.sql | 10 ++++++--- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index e14bc0c0548..c993abc9792 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -10372,6 +10372,8 @@ addFkRecurseReferenced(Constraint *fkconstraint, Relation rel, Oid deleteTriggerOid, updateTriggerOid; + Assert(CheckRelationLockedByMe(pkrel, ShareRowExclusiveLock, true)); + /* * Create the action triggers that enforce the constraint. */ @@ -19436,8 +19438,7 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, foreach(cell, fks) { ForeignKeyCacheInfo *fk = lfirst(cell); - HeapTuple contup, - parentConTup; + HeapTuple contup; Form_pg_constraint conform; Oid insertTriggerOid, updateTriggerOid; @@ -19455,13 +19456,6 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, continue; } - Assert(OidIsValid(conform->conparentid)); - parentConTup = SearchSysCache1(CONSTROID, - ObjectIdGetDatum(conform->conparentid)); - if (!HeapTupleIsValid(parentConTup)) - elog(ERROR, "cache lookup failed for constraint %u", - conform->conparentid); - /* * The constraint on this table must be marked no longer a child of * the parent's constraint, as do its check triggers. @@ -19502,7 +19496,6 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, Oid conffeqop[INDEX_MAX_KEYS]; int numfkdelsetcols; AttrNumber confdelsetcols[INDEX_MAX_KEYS]; - AttrMap *attmap; Relation refdRel; DeconstructFkConstraintRow(contup, @@ -19535,20 +19528,19 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, fkconstraint->old_pktable_oid = InvalidOid; fkconstraint->location = -1; - attmap = build_attrmap_by_name(RelationGetDescr(partRel), - RelationGetDescr(rel), - false); + /* set up colnames, used to generate the constraint name */ for (int i = 0; i < numfks; i++) { Form_pg_attribute att; att = TupleDescAttr(RelationGetDescr(partRel), - attmap->attnums[conkey[i] - 1] - 1); + conkey[i] - 1); + fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs, makeString(NameStr(att->attname))); } - refdRel = table_open(fk->confrelid, AccessShareLock); + refdRel = table_open(fk->confrelid, ShareRowExclusiveLock); addFkRecurseReferenced(fkconstraint, partRel, refdRel, @@ -19565,11 +19557,10 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, true, InvalidOid, InvalidOid, conform->conperiod); - table_close(refdRel, AccessShareLock); + table_close(refdRel, NoLock); /* keep lock till end of xact */ } ReleaseSysCache(contup); - ReleaseSysCache(parentConTup); } list_free_deep(fks); if (trigrel) diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out index b73e7dced8f..69994c98e32 100644 --- a/src/test/regress/expected/foreign_key.out +++ b/src/test/regress/expected/foreign_key.out @@ -2944,17 +2944,20 @@ CREATE SCHEMA fkpart12 CREATE TABLE fk_p ( id int, jd int, PRIMARY KEY(id, jd)) PARTITION BY list (id) CREATE TABLE fk_p_1 PARTITION OF fk_p FOR VALUES IN (1) PARTITION BY list (jd) CREATE TABLE fk_p_1_1 PARTITION OF fk_p_1 FOR VALUES IN (1) - CREATE TABLE fk_p_1_2 PARTITION OF fk_p_1 FOR VALUES IN (2) + CREATE TABLE fk_p_1_2 (x int, y int, jd int NOT NULL, id int NOT NULL) CREATE TABLE fk_p_2 PARTITION OF fk_p FOR VALUES IN (2) PARTITION BY list (jd) CREATE TABLE fk_p_2_1 PARTITION OF fk_p_2 FOR VALUES IN (1) CREATE TABLE fk_p_2_2 PARTITION OF fk_p_2 FOR VALUES IN (2) - CREATE TABLE fk_r_1 ( id int PRIMARY KEY, p_id int NOT NULL, p_jd int NOT NULL) + CREATE TABLE fk_r_1 ( p_jd int NOT NULL, x int, id int PRIMARY KEY, p_id int NOT NULL) CREATE TABLE fk_r_2 ( id int PRIMARY KEY, p_id int NOT NULL, p_jd int NOT NULL) PARTITION BY list (id) CREATE TABLE fk_r_2_1 PARTITION OF fk_r_2 FOR VALUES IN (2, 1) CREATE TABLE fk_r ( id int PRIMARY KEY, p_id int NOT NULL, p_jd int NOT NULL, FOREIGN KEY (p_id, p_jd) REFERENCES fk_p (id, jd) ) PARTITION BY list (id); SET search_path TO fkpart12; +ALTER TABLE fk_p_1_2 DROP COLUMN x, DROP COLUMN y; +ALTER TABLE fk_p_1 ATTACH PARTITION fk_p_1_2 FOR VALUES IN (2); +ALTER TABLE fk_r_1 DROP COLUMN x; INSERT INTO fk_p VALUES (1, 1); ALTER TABLE fk_r ATTACH PARTITION fk_r_1 FOR VALUES IN (1); ALTER TABLE fk_r ATTACH PARTITION fk_r_2 FOR VALUES IN (2); @@ -2993,7 +2996,7 @@ Foreign-key constraints: "fk_r_p_id_p_jd_fkey" FOREIGN KEY (p_id, p_jd) REFERENCES fk_p(id, jd) Number of partitions: 1 (Use \d+ to list them.) -INSERT INTO fk_r_1 VALUES (2, 1, 2); -- should fail +INSERT INTO fk_r_1 (id, p_id, p_jd) VALUES (2, 1, 2); -- should fail ERROR: insert or update on table "fk_r_1" violates foreign key constraint "fk_r_p_id_p_jd_fkey" DETAIL: Key (p_id, p_jd)=(1, 2) is not present in table "fk_p". DELETE FROM fk_p; -- should fail diff --git a/src/test/regress/sql/foreign_key.sql b/src/test/regress/sql/foreign_key.sql index 9b2a6b6bff7..2e710e419c2 100644 --- a/src/test/regress/sql/foreign_key.sql +++ b/src/test/regress/sql/foreign_key.sql @@ -2097,11 +2097,11 @@ CREATE SCHEMA fkpart12 CREATE TABLE fk_p ( id int, jd int, PRIMARY KEY(id, jd)) PARTITION BY list (id) CREATE TABLE fk_p_1 PARTITION OF fk_p FOR VALUES IN (1) PARTITION BY list (jd) CREATE TABLE fk_p_1_1 PARTITION OF fk_p_1 FOR VALUES IN (1) - CREATE TABLE fk_p_1_2 PARTITION OF fk_p_1 FOR VALUES IN (2) + CREATE TABLE fk_p_1_2 (x int, y int, jd int NOT NULL, id int NOT NULL) CREATE TABLE fk_p_2 PARTITION OF fk_p FOR VALUES IN (2) PARTITION BY list (jd) CREATE TABLE fk_p_2_1 PARTITION OF fk_p_2 FOR VALUES IN (1) CREATE TABLE fk_p_2_2 PARTITION OF fk_p_2 FOR VALUES IN (2) - CREATE TABLE fk_r_1 ( id int PRIMARY KEY, p_id int NOT NULL, p_jd int NOT NULL) + CREATE TABLE fk_r_1 ( p_jd int NOT NULL, x int, id int PRIMARY KEY, p_id int NOT NULL) CREATE TABLE fk_r_2 ( id int PRIMARY KEY, p_id int NOT NULL, p_jd int NOT NULL) PARTITION BY list (id) CREATE TABLE fk_r_2_1 PARTITION OF fk_r_2 FOR VALUES IN (2, 1) CREATE TABLE fk_r ( id int PRIMARY KEY, p_id int NOT NULL, p_jd int NOT NULL, @@ -2109,6 +2109,10 @@ CREATE SCHEMA fkpart12 ) PARTITION BY list (id); SET search_path TO fkpart12; +ALTER TABLE fk_p_1_2 DROP COLUMN x, DROP COLUMN y; +ALTER TABLE fk_p_1 ATTACH PARTITION fk_p_1_2 FOR VALUES IN (2); +ALTER TABLE fk_r_1 DROP COLUMN x; + INSERT INTO fk_p VALUES (1, 1); ALTER TABLE fk_r ATTACH PARTITION fk_r_1 FOR VALUES IN (1); @@ -2124,7 +2128,7 @@ ALTER TABLE fk_r DETACH PARTITION fk_r_2; \d fk_r_2 -INSERT INTO fk_r_1 VALUES (2, 1, 2); -- should fail +INSERT INTO fk_r_1 (id, p_id, p_jd) VALUES (2, 1, 2); -- should fail DELETE FROM fk_p; -- should fail ALTER TABLE fk_r ATTACH PARTITION fk_r_1 FOR VALUES IN (1); -- 2.39.5 --venjkcsjyivuur74--