Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jMCYw-0001pB-Ed for pgsql-hackers@arkaria.postgresql.org; Wed, 08 Apr 2020 15:24:22 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1jMCYv-00049d-28 for pgsql-hackers@arkaria.postgresql.org; Wed, 08 Apr 2020 15:24:21 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jMCYu-00049N-OC for pgsql-hackers@lists.postgresql.org; Wed, 08 Apr 2020 15:24:20 +0000 Received: from mail-qk1-x72b.google.com ([2607:f8b0:4864:20::72b]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1jMCYs-0002Ac-0M for pgsql-hackers@lists.postgresql.org; Wed, 08 Apr 2020 15:24:20 +0000 Received: by mail-qk1-x72b.google.com with SMTP id v7so479608qkc.0 for ; Wed, 08 Apr 2020 08:24:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=telsasoft-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:mime-version:content-disposition :user-agent; bh=E7Mt7EUT4RNv4hSIMa6WB3hPuKqFRlLk1aGGcahfHqI=; b=x2ua6EwTytVmN2STsq1oVTACIjXs2ku/A6B9A6oW8/HUaVBVi5nDw12aOiaH6x10F2 3SU8aXUwrz4QrU0tRTW0jNR6M0iP9rgkoGcaGOq2HCSB4Rcouhl+lQOmBKx61rK3wtVf o6LzO0X8UurTPlyRpyB9eE2Q/7rVBFO0GZKZof8FPy/QvYNVcHuNQPUXB0o7lQ9h9laS aN29xGByNjtZlQjQcEL5Pc2JX5xXwCV+KYU+4mRXPFy05Few+4aXrWheLj5hJl+BVhbR l98D9locJD2bAocdpVW8Amvv5qz3cZuZX6HfashXC0bhm8Ygl/dNt7KA/q0hUXW3Dtcw lRyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:mime-version :content-disposition:user-agent; bh=E7Mt7EUT4RNv4hSIMa6WB3hPuKqFRlLk1aGGcahfHqI=; b=RJBCEoU0qgaZBtr7nb4bJEESrzYU0nfTBf2dtXSna7cGXxHB/q2UAyYTWStQoVC1TQ pwYwpFEKP5RsCoNw2Y/Q6x7H9roidFp0dlrC7Ok1/20TAuJqs4zXUT4uphQY+HaQK0Dn TbxWvkIT0LKClIpmKkxPuPs70f0bSpwSL8jkB9Z/ZMh4IY9WsTIajXETRqO9tnYB30H+ flVLbZHIJu/C49LTNn61ia2Nod5HjoyMRdii3iVF8g0R837bC87jfDH/K6z5gQvCLvAS VVoCT52g3yOMhSLgLJhXOviLELofaoeOE77DkjvbGqSkAP98VzWjo3Qb7ZHMTfchsFnr wexw== X-Gm-Message-State: AGi0PuYNdhUeqPgia255rQ5V+yfjdUy/GFpTQ4XbqSiyFvJdBIgJ4P+F 9nXyFQ/dnXoJlF+z86c94S85jQ== X-Google-Smtp-Source: APiQypI48/j45PkI2yfJ0GnSDBJAuCn1PxfRoQciH65Kf61IyzImP3yZ1OnpR/p6Sd//BOJYlmQCQw== X-Received: by 2002:a05:620a:1292:: with SMTP id w18mr8234740qki.276.1586359455054; Wed, 08 Apr 2020 08:24:15 -0700 (PDT) Received: from pryzbyj (charmander.telsasoft.com. [50.244.222.1]) by smtp.gmail.com with ESMTPSA id r9sm2703312qke.5.2020.04.08.08.24.13 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 08 Apr 2020 08:24:14 -0700 (PDT) Received: by pryzbyj (Postfix, from userid 1000) id 8D692800897; Wed, 8 Apr 2020 10:24:12 -0500 (CDT) Date: Wed, 8 Apr 2020 10:24:12 -0500 From: Justin Pryzby To: pgsql-hackers@lists.postgresql.org Cc: Alvaro Herrera Subject: DETACH PARTITION and FOR EACH ROW triggers on partitioned tables Message-ID: <20200408152412.GZ2228@telsasoft.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="STPqjqpCrtky8aYs" Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --STPqjqpCrtky8aYs Content-Type: text/plain; charset=us-ascii Content-Disposition: inline This seems to be a bug in master, v12, and (probably) v11, where "FOR EACH FOR" was first allowed on partition tables (86f575948). I thought this would work like partitioned indexes (8b08f7d48), where detaching a partition makes its index non-inherited, and attaching a partition marks a pre-existing, matching partition as inherited rather than creating a new one. DROP TABLE t, t1; CREATE TABLE t(i int)PARTITION BY RANGE(i); CREATE TABLE t1 PARTITION OF t FOR VALUES FROM(1)TO(2); CREATE OR REPLACE FUNCTION trigf() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN END $$; CREATE TRIGGER trig AFTER INSERT ON t FOR EACH ROW EXECUTE FUNCTION trigf(); SELECT tgrelid::regclass, * FROM pg_trigger WHERE tgrelid='t1'::regclass; ALTER TABLE t DETACH PARTITION t1; ALTER TABLE t ATTACH PARTITION t1 FOR VALUES FROM (1)TO(2); ERROR: trigger "trig" for relation "t1" already exists DROP TRIGGER trig ON t1; ERROR: cannot drop trigger trig on table t1 because trigger trig on table t requires it HINT: You can drop trigger trig on table t instead. I remember these, but they don't seem to be relevant to this issue, which seems to be independant. 1fa846f1c9 Fix cloning of row triggers to sub-partitions b9b408c487 Record parents of triggers The commit for partitioned indexes talks about using an pre-existing index on the child as a "convenience gadget", puts indexes into pg_inherit, and introduces "ALTER INDEX..ATTACH PARTITION" and "CREATE INDEX..ON ONLY". It's probably rare for a duplicate index to be useful (unless rebuilding to be more optimal, which is probably not reasonably interspersed with altering inheritence). But I don't know if that's equally true for triggers. So I'm not sure what the intended behavior is, so I've stopped after implementing a partial fix. --STPqjqpCrtky8aYs Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0001-WIP-fix-detaching-tables-with-inherited-triggers.patch" From 2c31cac22178d904ee108b77f316886d1e2f6288 Mon Sep 17 00:00:00 2001 From: Justin Pryzby Date: Fri, 3 Apr 2020 22:43:26 -0500 Subject: [PATCH] WIP: fix detaching tables with inherited triggers --- src/backend/commands/tablecmds.c | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 037d457c3d..10a60e158f 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -16797,6 +16797,39 @@ ATExecDetachPartition(Relation rel, RangeVar *name) } table_close(classRel, RowExclusiveLock); + /* detach triggers too */ + { + /* XXX: relcache.c */ + ScanKeyData skey; + SysScanDesc scan; + HeapTuple trigtup; + Relation tgrel = table_open(TriggerRelationId, RowExclusiveLock); + + ScanKeyInit(&skey, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber, + F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(partRel))); + + scan = systable_beginscan(tgrel, TriggerRelidNameIndexId, + true, NULL, 1, &skey); + + while (HeapTupleIsValid(trigtup = systable_getnext(scan))) + { + Form_pg_trigger pg_trigger; + trigtup = heap_copytuple(trigtup); /* need a modifiable copy */ + pg_trigger = (Form_pg_trigger) GETSTRUCT(trigtup); + /* Set the trigger's parent to Invalid */ + if (!OidIsValid(pg_trigger->tgparentid)) + continue; + if (!pg_trigger->tgisinternal) + continue; + pg_trigger->tgparentid = InvalidOid; + pg_trigger->tgisinternal = false; + CatalogTupleUpdate(tgrel, &trigtup->t_self, trigtup); + heap_freetuple(trigtup); + } + systable_endscan(scan); + table_close(tgrel, RowExclusiveLock); + } + /* * Detach any foreign keys that are inherited. This includes creating * additional action triggers. -- 2.17.0 --STPqjqpCrtky8aYs--