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 1m8UGs-0000qi-2B for pgsql-novice@arkaria.postgresql.org; Tue, 27 Jul 2021 21:05:50 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1m8UGq-0003lz-JC for pgsql-novice@arkaria.postgresql.org; Tue, 27 Jul 2021 21:05:48 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1m8UGq-0003lW-AY for pgsql-novice@lists.postgresql.org; Tue, 27 Jul 2021 21:05:48 +0000 Received: from mout01.posteo.de ([185.67.36.65]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1m8UGk-0007OB-Ve for pgsql-novice@lists.postgresql.org; Tue, 27 Jul 2021 21:05:47 +0000 Received: from submission (posteo.de [89.146.220.130]) by mout01.posteo.de (Postfix) with ESMTPS id 30E46240026 for ; Tue, 27 Jul 2021 23:05:38 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=posteo.net; s=2017; t=1627419939; bh=yeeukqrbt0mhXJqU9hS2AE8CYqe3iKtj8gUMxjF1I94=; h=From:To:Cc:Subject:Date:From; b=UYN0aAe0cNokx4RAS7H9rYl96yv2YH3+EmVOXJcZC7lOzeSOz7oWqn6OS0bFbHoxG iEHuSB63kEVjnh9eFfWYBP/us2NRt4KJlNQBXibpAGDlXSE1ctPS6OZFjfuBZCdEKi DGptOHYg4z4rDR5DlRNNQh82sKNvduHbWxFwXXeu4lc4NtujL/Phxc+SRokkvQ7uE/ /+ZcRDnImvEZc0DyANWm3TV4/a9MmN+KoVYc5nKTse0Au68zMHXWoD6xV0ml1xrR4m jxhC9yFqBWcmm5jC1dKiSG34X4dPRKfq89MY5U/IAgABI8aAN2sigGMg/n2C61Yxc0 qYI9D+TYpf/bg== Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4GZ8TG2Z3sz9rxP; Tue, 27 Jul 2021 23:05:38 +0200 (CEST) From: "Nicolas Mitchell" To: "hubert depesz lubaczewski" Cc: pgsql-novice@lists.postgresql.org Subject: Re: Trigger function Date: Tue, 27 Jul 2021 21:05:26 +0000 Message-ID: <2D1DF30A-25BC-48CA-B502-D8B3147B9BEB@posteo.net> In-Reply-To: <20210727063805.GA28983@depesz.com> References: <30B8A3D0-8A87-40E2-BE40-31A17BA4B944@posteo.net> <20210727063805.GA28983@depesz.com> MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8"; format=flowed Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 27 Jul 2021, at 7:38, hubert depesz lubaczewski wrote: > *after* insert, not *before*. > But other than that yes. Apologies for the lengthy reply; I=E2=80=99ve done a lot of thinking toda= y. I cannot understand why it would be *after* insert: A required column in = a new host row (host.object) cannot be populated until a new row is = inserted into the object table. Therefore the function must (surely?) be = executed prior to an insert (on the host table). From the point of view of a user, the command they would issue is: =3D> INSERT INTO host (name, domain) VALUES ('gary', 1000001); I imagined the trigger/function taking the supplied information (name, = domain) and retrieving the value for host.object before insert. But when I have tried this with the following trigger/function = (BEFORE/AFTER), PG goes into a loop. The two associated sequences = (object, host) are incremented until I break the execution but no insert = happens in either table. My code is causing an endless loop. I=E2=80=99m = too = green to understand why! I=E2=80=99d be grateful for any hints to help me= on = my way. CREATE OR REPLACE FUNCTION public.func__host__bi() RETURNS trigger AS $$ begin WITH object_id AS (INSERT INTO public.object (type) VALUES ( ( SELECT obtype.id FROM public.obtype WHERE obtype.name LIKE 'host' ) ) RETURNING id) INSERT INTO host (name, domain, object) VALUES (NEW.name, NEW.domain, (SELECT * FROM object_id)); RETURN NEW; end $$ LANGUAGE 'plpgsql' CREATE TRIGGER trig__host_bi BEFORE INSERT <=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2= =80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94> or AFTER INSERT ON public."host" FOR EACH ROW EXECUTE PROCEDURE public.func__host__bi(); Later, and this is for another day, after reading your article (which = mentions view triggers) it occurred to me to try a trigger attached to a = view of the hosts table. I created a view and attached a trigger (only = INSTEAD OF allowed, noted) calling the same function: CREATE VIEW public.v_host ( id, "name", "domain", "object" ) AS SELECT host.id, host.name, host.domain, host.object FROM host; CREATE TRIGGER trig__v_host__bi INSTEAD OF INSERT ON public.v_host FOR EACH ROW EXECUTE PROCEDURE public.func__host__bi(); CREATE OR REPLACE FUNCTION public.func__host__bi() RETURNS trigger AS $$ begin WITH object_id AS (INSERT INTO public.object (type) VALUES ( ( SELECT obtype.id FROM public.obtype WHERE obtype.name LIKE 'host' ) ) RETURNING id) INSERT INTO host (name, domain, object) VALUES (NEW.name, NEW.domain, (SELECT * FROM object_id)); RETURN NEW; end $$ LANGUAGE 'plpgsql' The previous psql command would now be: =3D> INSERT INTO v__host (name, domain) VALUES ('gary', 1000001); Which succeeds when executed, - inserting a new object (of type host) - inserting a new host, with the object.id (host.object) of the newly = created object - incrementing the two sequences by one each > If I might suggest: > https://www.depesz.com/2012/11/14/how-i-learned-to-stop-worrying-and-lo= ve-the-triggers/ Thank you, this was really helpful. I expect to be referring back to it = in the future. Many thanks, Nic