Re: Trigger firing order

Lists: pgsql-general
From: "Alex Bolenok" <abolen(at)chat(dot)ru>
To: <pgsql-general(at)postgresql(dot)org>
Subject: Trigger firing order
Date: 2000-11-29 13:23:55
Message-ID: 007901c05a07$a4a60af0$0e02a8c0@artey.ru
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

Hello all,

I have a problem with PostgreSQL. Here is the description of the problem:

First, I create tables and triggers for them, so that after insert to one
table a row is inserted to another table.

CREATE TABLE t_foo (
foo_id SERIAL PRIMARY KEY,
foo_value NUMERIC NOT NULL
);

CREATE TABLE t_bar (
bar_foo INT4 NOT NULL REFERENCES t_foo (foo_id),
bar_state INT2 NOT NULL
);

CREATE FUNCTION fn_foo_ains()
RETURNS OPAQUE AS '
BEGIN
RAISE NOTICE ''fn_foo_ains: Start'';
INSERT
INTO t_bar (bar_foo, bar_state)
VALUES (NEW.foo_id, 1);

/* There will be code that examines table */
/* modified by fn_bar_ains() (see below) */

RAISE NOTICE ''fn_foo_ains: End'';
RETURN NULL;
END;
' LANGUAGE 'plpgsql';

CREATE TRIGGER trg_foo_ains
AFTER INSERT ON t_foo
FOR EACH ROW
EXECUTE PROCEDURE fn_foo_ains();

CREATE FUNCTION fn_bar_ains()
RETURNS OPAQUE AS '
BEGIN
RAISE NOTICE ''fn_bar_ains: Start'';

/* There will be code that modifies the third table */

RAISE NOTICE ''fn_bar_ains: End'';
RETURN NULL;
END;
' LANGUAGE 'plpgsql';

CREATE TRIGGER trg_bar_ains
AFTER INSERT
ON t_bar
FOR EACH ROW
EXECUTE PROCEDURE fn_bar_ains();

Then I insert a row. Here is output I get:

peroon=# INSERT INTO t_foo (foo_value) VALUES (2000);
NOTICE: fn_foo_ains: Start
NOTICE: fn_foo_ains: End
NOTICE: fn_bar_ains: Start
NOTICE: fn_bar_ains: End
INSERT 121365 1

So, when I do an "INSERT INTO t_bar" inside the "TRIGGER AFTER INSERT ON
t_foo", the trigger procedure on t_bar is executed only when the trigger
procedure on t_foo returns.

The behaviour I expect would be something like that:

NOTICE: fn_foo_ains: Start
NOTICE: fn_bar_ains: Start
NOTICE: fn_bar_ains: End
NOTICE: fn_foo_ains: End

, so that all changes made by fn_bar_ains() would be visible to
fn_foo_ains() after the "INSERT INTO t_bar" completes.

Is there any way to make the system work this way?

Thanks in advance,

Alex Bolenok.


From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: "Alex Bolenok" <abolen(at)chat(dot)ru>
Cc: Jan Wieck <JanWieck(at)Yahoo(dot)com>, pgsql-general(at)postgresql(dot)org
Subject: Re: Trigger firing order
Date: 2000-11-30 03:00:38
Message-ID: 3318.975553238@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

"Alex Bolenok" <abolen(at)chat(dot)ru> writes:
> peroon=# INSERT INTO t_foo (foo_value) VALUES (2000);
> NOTICE: fn_foo_ains: Start
> NOTICE: fn_foo_ains: End
> NOTICE: fn_bar_ains: Start
> NOTICE: fn_bar_ains: End

Looking at the code, it seems that all AFTER triggers are implicitly
handled as DEFERRED triggers, ie, they're queued up and executed at
end of statement. This seems wrong to me --- DEFERRED mode is useful,
certainly, but it shouldn't be the only form of AFTER trigger.

Also, it'd seem to me that DEFERRED mode ought to mean defer till end
of transaction, not just end of statement...

Jan, any comments here?

regards, tom lane