Thread: Why are triggers semi-deferred?

Why are triggers semi-deferred?

From
Philip Warner
Date:
At least in 7.3, triggered actions specified as AFTER seem to be deferred 
to the completion of the outer-most SQL statement. So, if two triggering 
statements are executed as part of a PLPGSQL procedure, they will not be 
executed until the outermost statement finishes.

As far as I can tell, this is not the way the spec says it should work:
    The <triggered SQL statement> of a triggered action is    effectively executed either immediately before or
immediately   after the trigger event, as determined by the specified    trigger action time.
 

In the case of statements executed sequentially inside a PLPGSQL procedure, 
I would have expected that the trigger would fire after the first 
triggering statement.

Have I missed a discussion of this (I have looked), or is this just a known 
problem?



----------------------------------------------------------------
Philip Warner                    |     __---_____
Albatross Consulting Pty. Ltd.   |----/       -  \
(A.B.N. 75 008 659 498)          |          /(@)   ______---_
Tel: (+61) 0500 83 82 81         |                 _________  \
Fax: (+61) 03 5330 3172          |                 ___________ |
Http://www.rhyme.com.au          |                /           \|                                 |    --________--
PGP key available upon request,  |  /
and from pgp5.ai.mit.edu:11371   |/



Re: Why are triggers semi-deferred?

From
Stephan Szabo
Date:
On Mon, 5 May 2003, Philip Warner wrote:

> At least in 7.3, triggered actions specified as AFTER seem to be deferred
> to the completion of the outer-most SQL statement. So, if two triggering
> statements are executed as part of a PLPGSQL procedure, they will not be
> executed until the outermost statement finishes.
>
> As far as I can tell, this is not the way the spec says it should work:
>
>      The <triggered SQL statement> of a triggered action is
>      effectively executed either immediately before or immediately
>      after the trigger event, as determined by the specified
>      trigger action time.
>
> In the case of statements executed sequentially inside a PLPGSQL procedure,
> I would have expected that the trigger would fire after the first
> triggering statement.

Actually, I think from sql99's description, for after row triggers it
should happen after the row is modified not after the statement as a
whole (so given two 2 row updates in a function you'd getupdate1,row1 afterrow1-1 update1,row2
afterrow1-2,afterstatement1update2,row1afterrow2-1 update2,row2 afterrow2-2,afterstatement2
 
)

I'd been thinking (this came up recently is a bug/query about the foreign
keys that Tom sent me) that it might be better to make times that the
triggers can run be choosable (with the spec behavior becoming default
eventually) because we've got backward compatibility issues and we've kind
overloaded the trigger system to do the foreign keys which have their own
timing issues.



Re: Why are triggers semi-deferred?

From
Philip Warner
Date:
At 08:20 AM 5/05/2003 -0700, Stephan Szabo wrote:
>Actually, I think from sql99's description, for after row triggers it
>should happen after the row is modified not after the statement as a
>whole (so given two 2 row updates in a function you'd get
>  update1,row1 afterrow1-1 update1,row2 afterrow1-2,afterstatement1
>  update2,row1 afterrow2-1 update2,row2 afterrow2-2,afterstatement2
>)

Totally agree (I think) -- I am not sure how to interpret your example. To 
(I hope) clarify: if a function has two update statements (A & B), each of 
which update two rows (1 & 2), I would expect the triggers to fire as:

Procedure Starts    Statement A executes:        Before Row 1        After Row 1        Before Row 2        After Row 2
      Statement Trigger for A    Statement B executes:        Before Row 1        After Row 1        Before Row 2
After Row 2        Statement Trigger for B
 
Procedure Ends

At the current time in 7.3, we have:

Procedure Starts    Statement A executes:        Before Row 1        Before Row 2    Statement B executes:
BeforeRow 1        Before Row 2
 
Procedure End
After Row 1
After Row 2
After Row 1
After Row 2

...which seems weird to me. Is this something that needs fixing in 7.3.3?



----------------------------------------------------------------
Philip Warner                    |     __---_____
Albatross Consulting Pty. Ltd.   |----/       -  \
(A.B.N. 75 008 659 498)          |          /(@)   ______---_
Tel: (+61) 0500 83 82 81         |                 _________  \
Fax: (+61) 03 5330 3172          |                 ___________ |
Http://www.rhyme.com.au          |                /           \|                                 |    --________--
PGP key available upon request,  |  /
and from pgp5.ai.mit.edu:11371   |/



Re: Why are triggers semi-deferred?

From
Philip Warner
Date:
At 08:20 AM 5/05/2003 -0700, Stephan Szabo wrote:
>it might be better to make times that the
>triggers can run be choosable (with the spec behavior becoming default
>eventually) because we've got backward compatibility issues and we've kind
>overloaded the trigger system to do the foreign keys which have their own
>timing issues.

I think you are right here too; we need some way to make the triggers 
function according to the spec, as well as to preserve compatibility for 
constraint settings -- at least constrint triggers should fire when the 
constraints expect it, and normal triggers should fire when the spec says 
they should fire.



----------------------------------------------------------------
Philip Warner                    |     __---_____
Albatross Consulting Pty. Ltd.   |----/       -  \
(A.B.N. 75 008 659 498)          |          /(@)   ______---_
Tel: (+61) 0500 83 82 81         |                 _________  \
Fax: (+61) 03 5330 3172          |                 ___________ |
Http://www.rhyme.com.au          |                /           \|                                 |    --________--
PGP key available upon request,  |  /
and from pgp5.ai.mit.edu:11371   |/



Re: Why are triggers semi-deferred?

From
Stephan Szabo
Date:
On Tue, 6 May 2003, Philip Warner wrote:

> At 08:20 AM 5/05/2003 -0700, Stephan Szabo wrote:
> >it might be better to make times that the
> >triggers can run be choosable (with the spec behavior becoming default
> >eventually) because we've got backward compatibility issues and we've kind
> >overloaded the trigger system to do the foreign keys which have their own
> >timing issues.
>
> I think you are right here too; we need some way to make the triggers
> function according to the spec, as well as to preserve compatibility for
> constraint settings -- at least constrint triggers should fire when the
> constraints expect it, and normal triggers should fire when the spec says
> they should fire.

Actually, we'll probably want to allow it for normal triggers as well.  I
think it's likely to break current triggers that people are using or at
least change semantics.  For example, triggers that were made by
users that are doing some checks that currently assume that the full
set of actions have already been done, or one that does stuff outside the
database that now has to worry about stuff that used to be before it
erroring after it (sure it was unsafe before but now it's more unsafe).
Some of these will be rewritable (esp if we get statement triggers that
can see new/old rowsets), but I don't know if we want to force that.

[from other message]
>...which seems weird to me. Is this something that needs fixing in 7.3.3?

I think it's likely to be too large to be safe to put into 7.3.x.  Just
changing the times isn't too hard I think (rather than unconditionally
adding to the queue, determine if its immediate and run it and put the
deferred ones into the queue I think) but that doesn't deal with the other
timing issues which should be part of that.



Re: Why are triggers semi-deferred?

From
Tom Lane
Date:
Stephan Szabo <sszabo@megazone23.bigpanda.com> writes:
> Actually, I think from sql99's description, for after row triggers it
> should happen after the row is modified not after the statement as a
> whole (so given two 2 row updates in a function you'd get
>  update1,row1 afterrow1-1 update1,row2 afterrow1-2,afterstatement1
>  update2,row1 afterrow2-1 update2,row2 afterrow2-2,afterstatement2
> )

[ scratches head ... ]  That seems a useless definition.  What is the
purpose of firing immediately after, rather than immediately before,
a row update?  Wouldn't you want to wait till end of statement so you
know that the whole statement is in fact going to complete (and not
die at some later row)?  What do you have immediately after the update
that you didn't have just before it?
        regards, tom lane



Re: Why are triggers semi-deferred?

From
Tom Lane
Date:
Philip Warner <pjw@rhyme.com.au> writes:
> ...which seems weird to me. Is this something that needs fixing in 7.3.3?

It would be a really bad idea to make such a significant change in
trigger behavior in a dot-release ... think of it as a 7.4 proposal,
instead.  (Or maybe 7.5, considering how close the 7.4 feature freeze
date is.)
        regards, tom lane



Re: Why are triggers semi-deferred?

From
Philip Warner
Date:
At 12:09 PM 5/05/2003 -0400, Tom Lane wrote:
>think of it as a 7.4 proposal,
>instead.  (Or maybe 7.5, considering how close the 7.4 feature freeze
>date is.)

Good point. How close is it? It would be good to see this fixed in 7.4.


----------------------------------------------------------------
Philip Warner                    |     __---_____
Albatross Consulting Pty. Ltd.   |----/       -  \
(A.B.N. 75 008 659 498)          |          /(@)   ______---_
Tel: (+61) 0500 83 82 81         |                 _________  \
Fax: (+61) 03 5330 3172          |                 ___________ |
Http://www.rhyme.com.au          |                /           \|                                 |    --________--
PGP key available upon request,  |  /
and from pgp5.ai.mit.edu:11371   |/



Re: Why are triggers semi-deferred?

From
Philip Warner
Date:
At 12:07 PM 5/05/2003 -0400, Tom Lane wrote:
>Wouldn't you want to wait till end of statement so you
>know that the whole statement is in fact going to complete (and not
>die at some later row)?

So you are suggesting:

Procedure Starts    Statement A executes:        Before Row 1            Update Row 1        Before Row 2
UpdateRow 2        After Row 1        After Row 2        Statement Trigger for A    Statement B executes:        Before
Row1            Update Row 1        Before Row 2            Update Row 2        After Row 1        After Row 2
StatementTrigger for B
 
Procedure Ends

This seems like a nice optimization, but probably disagrees with the spec 
since we would be deferring the triggerred action (slightly). From a users 
point of view, I would be happy with it, and even prefer it to my 
interpretation of the spec.

But in the case of multi-row updates, won't it be expensive to keep all the 
context?


----------------------------------------------------------------
Philip Warner                    |     __---_____
Albatross Consulting Pty. Ltd.   |----/       -  \
(A.B.N. 75 008 659 498)          |          /(@)   ______---_
Tel: (+61) 0500 83 82 81         |                 _________  \
Fax: (+61) 03 5330 3172          |                 ___________ |
Http://www.rhyme.com.au          |                /           \|                                 |    --________--
PGP key available upon request,  |  /
and from pgp5.ai.mit.edu:11371   |/



Re: Why are triggers semi-deferred?

From
Tom Lane
Date:
Philip Warner <pjw@rhyme.com.au> writes:
> But in the case of multi-row updates, won't it be expensive to keep all the 
> context?

We do that already for AFTER triggers.  The question is just when the
trigger ought to be fired.
        regards, tom lane



Re: Why are triggers semi-deferred?

From
Tom Lane
Date:
Philip Warner <pjw@rhyme.com.au> writes:
>> instead.  (Or maybe 7.5, considering how close the 7.4 feature freeze
>> date is.)

> Good point. How close is it? It would be good to see this fixed in 7.4.

The target is to go beta June 1, so we need to freeze features probably
a week or two before that ... in other words, Real Soon Now.
        regards, tom lane



Re: Why are triggers semi-deferred?

From
Stephan Szabo
Date:
On Mon, 5 May 2003, Tom Lane wrote:

> Stephan Szabo <sszabo@megazone23.bigpanda.com> writes:
> > Actually, I think from sql99's description, for after row triggers it
> > should happen after the row is modified not after the statement as a
> > whole (so given two 2 row updates in a function you'd get
> >  update1,row1 afterrow1-1 update1,row2 afterrow1-2,afterstatement1
> >  update2,row1 afterrow2-1 update2,row2 afterrow2-2,afterstatement2
> > )
>
> [ scratches head ... ]  That seems a useless definition.  What is the
> purpose of firing immediately after, rather than immediately before,
> a row update?  Wouldn't you want to wait till end of statement so you
> know that the whole statement is in fact going to complete (and not
> die at some later row)?  What do you have immediately after the update
> that you didn't have just before it?

You're right, I'd misread "the trigger event" as being a row change for a
row trigger (go figure).  However, looking at it, then I'm not sure our
before row trigger timing is correct then.  It seems from 14.14 for a
delete example that the timing is supposed to be something like:
before trigger 1before trigger 2delete 1delete 2after trigger 1after trigger 2

rather than:before trigger 1delete 1before trigger 2delete 2after trigger 1after trigger 2



Re: Why are triggers semi-deferred?

From
Bruce Momjian
Date:
I am trying to figure out whether there is a TODO item in this thread. 

The basis of the discussion appeared to be whether we are honoring the
spec by executing before/after statement/row/constraint triggers
properly, and if we are not, is it desirable/significant if we break the
spec.

Which need changes?
                  Before      |      After
Statement                      |
Row                            |
Constraint                    


Does anyone have answers for these?  I read the thread and don't 100%
understand it all.

---------------------------------------------------------------------------

Stephan Szabo wrote:
> 
> On Mon, 5 May 2003, Tom Lane wrote:
> 
> > Stephan Szabo <sszabo@megazone23.bigpanda.com> writes:
> > > Actually, I think from sql99's description, for after row triggers it
> > > should happen after the row is modified not after the statement as a
> > > whole (so given two 2 row updates in a function you'd get
> > >  update1,row1 afterrow1-1 update1,row2 afterrow1-2,afterstatement1
> > >  update2,row1 afterrow2-1 update2,row2 afterrow2-2,afterstatement2
> > > )
> >
> > [ scratches head ... ]  That seems a useless definition.  What is the
> > purpose of firing immediately after, rather than immediately before,
> > a row update?  Wouldn't you want to wait till end of statement so you
> > know that the whole statement is in fact going to complete (and not
> > die at some later row)?  What do you have immediately after the update
> > that you didn't have just before it?
> 
> You're right, I'd misread "the trigger event" as being a row change for a
> row trigger (go figure).  However, looking at it, then I'm not sure our
> before row trigger timing is correct then.  It seems from 14.14 for a
> delete example that the timing is supposed to be something like:
> 
>  before trigger 1
>  before trigger 2
>  delete 1
>  delete 2
>  after trigger 1
>  after trigger 2
> 
> rather than:
>  before trigger 1
>  delete 1
>  before trigger 2
>  delete 2
>  after trigger 1
>  after trigger 2
> 
> 
> ---------------------------(end of broadcast)---------------------------
> TIP 5: Have you checked our extensive FAQ?
> 
> http://www.postgresql.org/docs/faqs/FAQ.html
> 

--  Bruce Momjian                        |  http://candle.pha.pa.us pgman@candle.pha.pa.us               |  (610)
359-1001+  If your life is a hard drive,     |  13 Roberts Road +  Christ can be your backup.        |  Newtown Square,
Pennsylvania19073
 


Re: Why are triggers semi-deferred?

From
Philip Warner
Date:
At 11:51 PM 1/06/2003 -0400, Bruce Momjian wrote:
>Does anyone have answers for these?  I read the thread and don't 100%
>understand it all.

My belief is that at least ROW triggers need fixing (7.3 doesn't have 
statement, not sure about 7.4).

Currently, if you write a plpgsql procedure which calls more than one 
insert/update/delete statements, the AFTER triggers for all of these 
statements will not fire until after the procedure exits. They should fire 
either just after each row is updated, or just after the most immediately 
enclosing statement executes. I think the thread wanted the latter.

So, if we have a table with two rows, and a BEFORE and AFTER trigger, and a 
plpgsql procedure that updates all rows twice, then we should have:

procedure called  procedure executes first update    before trigger fires(row 1)    before trigger fires(row 2)
row1 updated       row 2 updated    after trigger fires(row 1)    after trigger fires(row 2)  procedure executes second
update   before trigger fires(row 1)    before trigger fires(row 2)       row 1 updated       row 2 updated    after
triggerfires(row 1)    after trigger fires(row 2)
 
procedure exits

What we have in 7.3 is:

procedure called  procedure executes first update    before trigger fires(row 1)    before trigger fires(row 2)
row1 updated       row 2 updated  procedure executes second update    before trigger fires(row 1)    before trigger
fires(row2)       row 1 updated       row 2 updated
 
procedure exits
after trigger fires(row 1)
after trigger fires(row 2)
after trigger fires(row 1)
after trigger fires(row 2)

IIRC, the thread did not really discuss whether do intersperse the BEFORE 
executions with the updates, but doing them all before seems consistent.

Apologies is this has been covered elsewhere...








----------------------------------------------------------------
Philip Warner                    |     __---_____
Albatross Consulting Pty. Ltd.   |----/       -  \
(A.B.N. 75 008 659 498)          |          /(@)   ______---_
Tel: (+61) 0500 83 82 81         |                 _________  \
Fax: (+61) 03 5330 3172          |                 ___________ |
Http://www.rhyme.com.au          |                /           \|                                 |    --________--
PGP key available upon request,  |  /
and from pgp5.ai.mit.edu:11371   |/



Re: Why are triggers semi-deferred?

From
Philip Warner
Date:
At 10:38 AM 12/07/2003 -0700, Stephan Szabo wrote:
>  deferred after trigger row 1
>  deferred after trigger #2 row a
>  deferred after trigger row 2
>  deferred after trigger #2 row b

I'd vote for this; ie. make them execute in the same order they would 
execute if they were not deferred. Otherwise you open up all sorts of weird 
application errors if a trigger is deferred/not-deferred.


----------------------------------------------------------------
Philip Warner                    |     __---_____
Albatross Consulting Pty. Ltd.   |----/       -  \
(A.B.N. 75 008 659 498)          |          /(@)   ______---_
Tel: (+61) 0500 83 82 81         |                 _________  \
Fax: (+61) 03 5330 3172          |                 ___________ |
Http://www.rhyme.com.au          |                /           \|                                 |    --________--
PGP key available upon request,  |  /
and from pgp5.ai.mit.edu:11371   |/



Re: Why are triggers semi-deferred?

From
Bruce Momjian
Date:
Added to TODO:

* Have AFTER triggers execute after the appropriate SQL statement in a function, not at the end of the function


---------------------------------------------------------------------------

Philip Warner wrote:
> At 11:51 PM 1/06/2003 -0400, Bruce Momjian wrote:
> >Does anyone have answers for these?  I read the thread and don't 100%
> >understand it all.
> 
> My belief is that at least ROW triggers need fixing (7.3 doesn't have 
> statement, not sure about 7.4).
> 
> Currently, if you write a plpgsql procedure which calls more than one 
> insert/update/delete statements, the AFTER triggers for all of these 
> statements will not fire until after the procedure exits. They should fire 
> either just after each row is updated, or just after the most immediately 
> enclosing statement executes. I think the thread wanted the latter.
> 
> So, if we have a table with two rows, and a BEFORE and AFTER trigger, and a 
> plpgsql procedure that updates all rows twice, then we should have:
> 
> procedure called
>    procedure executes first update
>      before trigger fires(row 1)
>      before trigger fires(row 2)
>         row 1 updated
>         row 2 updated
>      after trigger fires(row 1)
>      after trigger fires(row 2)
>    procedure executes second update
>      before trigger fires(row 1)
>      before trigger fires(row 2)
>         row 1 updated
>         row 2 updated
>      after trigger fires(row 1)
>      after trigger fires(row 2)
> procedure exits
> 
> What we have in 7.3 is:
> 
> procedure called
>    procedure executes first update
>      before trigger fires(row 1)
>      before trigger fires(row 2)
>         row 1 updated
>         row 2 updated
>    procedure executes second update
>      before trigger fires(row 1)
>      before trigger fires(row 2)
>         row 1 updated
>         row 2 updated
> procedure exits
> after trigger fires(row 1)
> after trigger fires(row 2)
> after trigger fires(row 1)
> after trigger fires(row 2)
> 
> IIRC, the thread did not really discuss whether do intersperse the BEFORE 
> executions with the updates, but doing them all before seems consistent.
> 
> Apologies is this has been covered elsewhere...
> 
> 
> 
> 
> 
> 
> 
> 
> ----------------------------------------------------------------
> Philip Warner                    |     __---_____
> Albatross Consulting Pty. Ltd.   |----/       -  \
> (A.B.N. 75 008 659 498)          |          /(@)   ______---_
> Tel: (+61) 0500 83 82 81         |                 _________  \
> Fax: (+61) 03 5330 3172          |                 ___________ |
> Http://www.rhyme.com.au          |                /           \|
>                                   |    --________--
> PGP key available upon request,  |  /
> and from pgp5.ai.mit.edu:11371   |/
> 
> 

--  Bruce Momjian                        |  http://candle.pha.pa.us pgman@candle.pha.pa.us               |  (610)
359-1001+  If your life is a hard drive,     |  13 Roberts Road +  Christ can be your backup.        |  Newtown Square,
Pennsylvania19073