Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.89) (envelope-from ) id 1etko1-0005Es-O2 for pgsql-hackers@arkaria.postgresql.org; Thu, 08 Mar 2018 01:57:17 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1etko0-0002jj-4w for pgsql-hackers@arkaria.postgresql.org; Thu, 08 Mar 2018 01:57:16 +0000 Received: from makus.postgresql.org ([2001:4800:1501:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.89) (envelope-from ) id 1etknz-0002jX-Qy for pgsql-hackers@lists.postgresql.org; Thu, 08 Mar 2018 01:57:15 +0000 Received: from mail-qk0-x242.google.com ([2607:f8b0:400d:c09::242]) by makus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1etknw-0007qx-HZ for pgsql-hackers@postgresql.org; Thu, 08 Mar 2018 01:57:14 +0000 Received: by mail-qk0-x242.google.com with SMTP id b130so5091610qkg.9 for ; Wed, 07 Mar 2018 17:57:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=2ndquadrant-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:mime-version:content-disposition :content-transfer-encoding:in-reply-to:user-agent; bh=pZYygbku5IVeQhFCj4PwyQAHjcZ8PB9j+nDNOdzOkUo=; b=hBFtjaNFq1OsujkQUdMGG5V7C0s6GuXXPlfN5YcVdlXE8GkK4RW6bOf2gxyS/VHcDH tNWwyCh9D0HnSiEKElKe5VosSJo3PAUMLRSJOyTORkWg2nYMwNGpybjFQcD+pBBf3W5C BJ4zSm5yDQ7tWamOrVurpS5RV254ceNXoYqMK2ywTEm7djnn9pd7bPCjPoOIIDOrwc+q 4LUZT/uB7Mp/xZeWz9Vy8BIYGBD1xRVBouDUkkxy4q80ulUu6fGUg9UjgrBo/lPuSMS5 cfQWC9sS5rgoZAU0ULiPQvvPbvAjvegX/yHp7t287Qpa+34tw22jKBcewg8bYABu4QtP jyfg== 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:content-transfer-encoding:in-reply-to :user-agent; bh=pZYygbku5IVeQhFCj4PwyQAHjcZ8PB9j+nDNOdzOkUo=; b=DojSNiaK4H2Ralii7AThTy+z+qXv+dnvV6oFNxm4gqZpfGfjouLY0Y5790sR1eUEBw dVEpOmqkBya65RE1upeI5hmngkwD1Fdtmv2xBZ9TCzwZRgf2cJ9YsDMUafTx6T0hkWWz nQwfoj14UIXjK1ok2n/ifiIKUi1vN+WT+RqxBoJc+SzzF/F6F3ISX1Fy7BNuQspkrVtF +5FsE7XuUPjXmwmG3/HuhZqlk2YI6ihaNL33tEYL6apfn09/7tCyOzdMxj6Xd6pbzWdZ Z40KLQ9CU3bb6sXVcZKn4ctCgeetA2gxU0tfkXrAuV9CZpHQmKFEhVDrulhdMTn8lRXx /fLw== X-Gm-Message-State: AElRT7H87WAk2WGAS9BTR+WJQN1Vtx0++Ws4AmTK2JdecUPF+HRvwIP7 GK9Lqry/HRrCYqis4uttsH3mkw== X-Google-Smtp-Source: AG47ELteQ82zIcLESl1ZkIsHl6swXZLMvKhoWSB6jtD0eQaHLQgR39MW3Qb1nyE+p4xmr5VV1cfvbA== X-Received: by 10.55.22.24 with SMTP id g24mr37774011qkh.302.1520474231456; Wed, 07 Mar 2018 17:57:11 -0800 (PST) Received: from alvin.alvh.no-ip.org ([190.121.34.242]) by smtp.gmail.com with ESMTPSA id r22sm13145723qkr.21.2018.03.07.17.57.10 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 07 Mar 2018 17:57:10 -0800 (PST) Received: by alvin.alvh.no-ip.org (Postfix, from userid 1000) id 6988E603; Wed, 7 Mar 2018 22:57:08 -0300 (-03) Date: Wed, 7 Mar 2018 22:57:08 -0300 From: Alvaro Herrera To: Robert Haas Cc: Peter Eisentraut , Pg Hackers , Simon Riggs Subject: Re: FOR EACH ROW triggers on partitioned tables Message-ID: <20180308015708.kc755cmaadpxgpyg@alvherre.pgsql> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <20180307171753.27xnxnjhlphur6bs@alvherre.pgsql> User-Agent: NeoMutt/20170306-137-4415bd-dirty (1.8.0) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk Alvaro Herrera wrote: > I reserve the right to revise this further, as I'm going to spend a > couple of hours looking at it this afternoon, particularly to see how > concurrent DDL behaves, but I don't see anything obviously wrong with > it. I do now. TLDR; I'm afraid this cute idea crashed and burned, so I'm back to the idea of just cloning the pg_trigger row for each partition. The reason for the failure is pg_trigger->tgqual, which is an expression tree. In most cases, when set, that expression will contain references to columns of the table, in the form of a varattno. But this varattno references the column number of the partitioned table; and if the partition happens to require some attribute mapping, we're screwed because there is no way to construct that without forming the partitioned table's tuple descriptor. But we can't do that without grabbing a lock on the partitioned table; and we can't do that because we would incur the deadlock risk Robert was talking about. An example that causes the problem is: create table parted_irreg (fd int, a int, fd2 int, b text) partition by range (b); alter table parted_irreg drop column fd, drop column fd2; create table parted1_irreg (b text, fd int, a int); alter table parted1_irreg drop column fd; alter table parted_irreg attach partition parted1_irreg for values from ('aaaa') to ('bbbb'); create trigger parted_trig after insert on parted_irreg for each row when (new.a % 1 = 0) execute procedure trigger_notice_irreg(); insert into parted_irreg values (1, 'aardvark'); insert into parted1_irreg values ('aardwolf', 2); drop table parted_irreg; drop function trigger_notice_irreg(); Both inserts fail thusly: ERROR: attribute 2 of type parted1_irreg has been dropped Now, I can fix the first failure by taking advantage of ResultRelInfo->ri_PartitionRoot during trigger execution; it's easy and trouble-free to call map_variable_attnos() using that relation. But in the second insert, ri_PartitionRoot is null (because of inserting into the partition directly), so we have no relation to refer to for map_variable_attnos(). I think it gets worse: if you have a three-level partitioning scheme, and define the trigger in the second one, there is no relation either. Another option I think would be to always keep in the trigger descriptor ("somehow"), an open Relation on which the trigger is defined. But this has all sorts of problems also, so I'm not doing that. I guess another option is to store a column map somewhere. So, unless someone has a brilliant idea on how to construct a column mapping from partitioned table to partition, I'm going back to the design I was proposing earlier, ie., creating individual pg_trigger rows for each partition that are essentially adjusted copies of the ones for the partitioned table. The only missing thing in that one was having ALTER TABLE ENABLE/DISABLE for a trigger on the partitioned table cascade to the partitions; I'll see about that. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services