Thread: Review: pre-commit triggers

Review: pre-commit triggers

From
Ian Lawrence Barwick
Date:
Review for Andrew Dunstan's patch in CF 2013-11:
 https://commitfest.postgresql.org/action/patch_view?id=1312

This review is more from a usage point of view, I would like
to spend more time looking at the code but only so many hours in a day,
etcetera; I hope this is useful as-is.


Submission review
-----------------
* Is the patch in a patch format which has context?
Yes

* Does it apply cleanly to the current git master?
Yes. No new files are introduced by this patch.

* Does it include reasonable tests, necessary doc patches, etc?
Documentation patches included, but no tests. (I have a feeling it
might be necessary to add a FAQ somewhere as to why there's
no transaction rollback trigger).


Usability review
----------------
* Does the patch actually implement that?
Yes.

* Do we want that?
There is an item in the todo-list "Add database and transaction-level triggers";
the linked thread:
  http://archives.postgresql.org/pgsql-hackers/2008-05/msg00620.php

from 2008 doesn't seem too receptive to the idea, but this time round
there don't seem to be any particular objections. Personally I don't
have a use-case but it certainly looks like a useful compatibility
feature when porting from other databases. Andrew mentions
porting from Firebird; for reference this is the relevant Firebird
documentation:
 http://www.firebirdsql.org/refdocs/langrefupd21-ddl-trigger.html

* Do we already have it?
No.

* Does it follow SQL spec, or the community-agreed behavior?
Not sure about the SQL spec. The "Compatibility" section of the
CREATE TRIGGER doc page doesn't mention anything along these lines.
 http://www.postgresql.org/docs/9.3/static/sql-createtrigger.html#SQL-CREATETRIGGER-COMPATIBILITY

* Does it include pg_dump support (if applicable)?
Yes


Feature test
------------

* Does the feature work as advertised?
Yes.

* Are there corner cases the author has failed to consider?

I'm not sure whether it's intended behaviour, but if the
commit trigger itself fails, there's an implicit rollback, e.g.:
 postgres=# BEGIN ; BEGIN postgres=*# INSERT INTO foo (id) VALUES (1); INSERT 0 1 postgres=*# COMMIT ; NOTICE:
Pre-committrigger called ERROR:  relation "bar" does not exist LINE 1: SELECT foo FROM bar^ QUERY:  SELECT foo FROM bar
CONTEXT: PL/pgSQL function pre_commit_trigger() line 4 at EXECUTE statement postgres=#
 

I'd expect this to lead to a failed transaction block,
or at least some sort of notice that the transaction itself
has been rolled back.

Note that 'DROP FUNCTION broken_trigger_function() CASCADE' will remove
the broken function without having to resort to single user mode so
it doesn't seem like an error in the commit trigger itself will
necessarily lead to an intractable situation.


* Are there any assertion failures or crashes?
No.


Performance review
------------------

* Does the patch slow down simple tests?
No.

* If it claims to improve performance, does it?
n/a

* Does it slow down other things?
No.


Coding review
-------------

* Does it follow the project coding guidelines?
Yes.

* Are there portability issues?
I don't see any.

* Will it work on Windows/BSD etc?
Tested on OS X and Linux. I don't see anything, e.g. system calls, which
might prevent it working on Windows.

* Does it do what it says, correctly?
As far as I can tell, yes.

* Does it produce compiler warnings?
No.

* Can you make it crash?
So far, no.


Architecture review
-------------------

* Is everything done in a way that fits together coherently with other
features/modules?
The changes are not all that complex and I don't see any issues, however
I'm not very familiar with that area of the code (but hey, that's why I'm
taking a look) so I might be missing something.

* Are there interdependencies that can cause problems?
I can't see any.


Additional notes
----------------

A sample transaction commit trigger:
 CREATE OR REPLACE FUNCTION pre_commit_trigger()   RETURNS EVENT_TRIGGER   LANGUAGE 'plpgsql' AS $$ BEGIN   RAISE
NOTICE'Pre-commit trigger called'; END; $$;
 
 CREATE EVENT TRIGGER trg_pre_commit ON transaction_commit    EXECUTE PROCEDURE pre_commit_trigger();


Some relevant links:
 http://www.postgresql.org/docs/9.3/interactive/event-triggers.html
http://www.postgresql.org/docs/9.3/interactive/sql-createeventtrigger.html
http://www.postgresql.org/docs/9.3/interactive/sql-prepare-transaction.html
http://en.wikipedia.org/wiki/Database_trigger


Regards

Ian Barwick



Re: Review: pre-commit triggers

From
Andrew Dunstan
Date:
On 11/18/2013 09:39 AM, Ian Lawrence Barwick wrote:
> Review for Andrew Dunstan's patch in CF 2013-11:
>
>    https://commitfest.postgresql.org/action/patch_view?id=1312
>
> This review is more from a usage point of view, I would like
> to spend more time looking at the code but only so many hours in a day,
> etcetera; I hope this is useful as-is.


Many thanks for the fast review.

>
> * Does it include reasonable tests, necessary doc patches, etc?
> Documentation patches included, but no tests. (I have a feeling it
> might be necessary to add a FAQ somewhere as to why there's
> no transaction rollback trigger).

I'll add some tests very shortly, and see about adding that to the docs.


> * Are there corner cases the author has failed to consider?
>
> I'm not sure whether it's intended behaviour, but if the
> commit trigger itself fails, there's an implicit rollback, e.g.:
>
>    postgres=# BEGIN ;
>    BEGIN
>    postgres=*# INSERT INTO foo (id) VALUES (1);
>    INSERT 0 1
>    postgres=*# COMMIT ;
>    NOTICE:  Pre-commit trigger called
>    ERROR:  relation "bar" does not exist
>    LINE 1: SELECT foo FROM bar
>   ^
>    QUERY:  SELECT foo FROM bar
>    CONTEXT:  PL/pgSQL function pre_commit_trigger() line 4 at EXECUTE statement
>    postgres=#
>
> I'd expect this to lead to a failed transaction block,
> or at least some sort of notice that the transaction itself
> has been rolled back.


I'll check on this.

>
> Note that 'DROP FUNCTION broken_trigger_function() CASCADE' will remove
> the broken function without having to resort to single user mode so
> it doesn't seem like an error in the commit trigger itself will
> necessarily lead to an intractable situation.


Given that, do we want to keep the bar on these operating in single user 
mode? I can easily drop it and just document this way out of difficulty.


cheers

andrew



Re: Review: pre-commit triggers

From
Dimitri Fontaine
Date:
Andrew Dunstan <andrew@dunslane.net> writes:
> Given that, do we want to keep the bar on these operating in single user
> mode? I can easily drop it and just document this way out of difficulty.

Currently Event Triggers are disabled in single user mode, in parts
because operating them require accessing to a catalog index, which might
be corrupted and the reason why you're in single user mode in the first
place.

So please keep your new event trigger disabled in single user mode.
 http://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=cd3413ec3683918c9cb9cfb39ae5b2c32f231e8b

Regards, and thanks for this new Event Trigger!
-- 
Dimitri Fontaine
http://2ndQuadrant.fr     PostgreSQL : Expertise, Formation et Support



Re: Review: pre-commit triggers

From
Robert Haas
Date:
On Mon, Nov 18, 2013 at 9:39 AM, Ian Lawrence Barwick <barwick@gmail.com> wrote:
>   postgres=# BEGIN ;
>   BEGIN
>   postgres=*# INSERT INTO foo (id) VALUES (1);
>   INSERT 0 1
>   postgres=*# COMMIT ;
>   NOTICE:  Pre-commit trigger called
>   ERROR:  relation "bar" does not exist
>   LINE 1: SELECT foo FROM bar
>  ^
>   QUERY:  SELECT foo FROM bar
>   CONTEXT:  PL/pgSQL function pre_commit_trigger() line 4 at EXECUTE statement
>   postgres=#
>
> I'd expect this to lead to a failed transaction block,
> or at least some sort of notice that the transaction itself
> has been rolled back.

Ending up in a failed transaction block would be wrong.  If the user
does a BEGIN, a bunch of stuff, and a COMMIT, they're entitled to
assume without checking that they are no longer in a transaction
block.  The COMMIT may have actually performed a ROLLBACK, but one way
or the other the transaction block will have ended.  This is important
for things like psql <
my-dumb-script-with-several-begin-commit-blocks.

It is a little less clear whether it's best for the COMMIT to return
an ERROR message or something else, but I think the ERROR is probably
the best solution.  There is already commit-time code that can fail
today, so there should be precedent here.  And I suspect anything
other than ERROR will be really messy to implement.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: Review: pre-commit triggers

From
Andrew Dunstan
Date:
On 11/19/2013 10:58 AM, Robert Haas wrote:
> On Mon, Nov 18, 2013 at 9:39 AM, Ian Lawrence Barwick <barwick@gmail.com> wrote:
>>    postgres=# BEGIN ;
>>    BEGIN
>>    postgres=*# INSERT INTO foo (id) VALUES (1);
>>    INSERT 0 1
>>    postgres=*# COMMIT ;
>>    NOTICE:  Pre-commit trigger called
>>    ERROR:  relation "bar" does not exist
>>    LINE 1: SELECT foo FROM bar
>>   ^
>>    QUERY:  SELECT foo FROM bar
>>    CONTEXT:  PL/pgSQL function pre_commit_trigger() line 4 at EXECUTE statement
>>    postgres=#
>>
>> I'd expect this to lead to a failed transaction block,
>> or at least some sort of notice that the transaction itself
>> has been rolled back.
> Ending up in a failed transaction block would be wrong.  If the user
> does a BEGIN, a bunch of stuff, and a COMMIT, they're entitled to
> assume without checking that they are no longer in a transaction
> block.  The COMMIT may have actually performed a ROLLBACK, but one way
> or the other the transaction block will have ended.  This is important
> for things like psql <
> my-dumb-script-with-several-begin-commit-blocks.
>
> It is a little less clear whether it's best for the COMMIT to return
> an ERROR message or something else, but I think the ERROR is probably
> the best solution.  There is already commit-time code that can fail
> today, so there should be precedent here.  And I suspect anything
> other than ERROR will be really messy to implement.
>



OK, you've convinced me.

cheers

andrew



Re: Review: pre-commit triggers

From
Tom Lane
Date:
Robert Haas <robertmhaas@gmail.com> writes:
> On Mon, Nov 18, 2013 at 9:39 AM, Ian Lawrence Barwick <barwick@gmail.com> wrote:
>> I'd expect this to lead to a failed transaction block,
>> or at least some sort of notice that the transaction itself
>> has been rolled back.

> Ending up in a failed transaction block would be wrong.  If the user
> does a BEGIN, a bunch of stuff, and a COMMIT, they're entitled to
> assume without checking that they are no longer in a transaction
> block.

Absolutely.  There are plenty of ways to fail at COMMIT already,
eg deferred foreign key constraints.  This shouldn't act any
different.
        regards, tom lane



Re: Review: pre-commit triggers

From
Ian Lawrence Barwick
Date:
2013/11/20 Tom Lane <tgl@sss.pgh.pa.us>:
> Robert Haas <robertmhaas@gmail.com> writes:
>> On Mon, Nov 18, 2013 at 9:39 AM, Ian Lawrence Barwick <barwick@gmail.com> wrote:
>>> I'd expect this to lead to a failed transaction block,
>>> or at least some sort of notice that the transaction itself
>>> has been rolled back.
>
>> Ending up in a failed transaction block would be wrong.  If the user
>> does a BEGIN, a bunch of stuff, and a COMMIT, they're entitled to
>> assume without checking that they are no longer in a transaction
>> block.
>
> Absolutely.  There are plenty of ways to fail at COMMIT already,
> eg deferred foreign key constraints.  This shouldn't act any
> different.

Ah OK, I see how that works. Thanks for the explanation.

Ian Barwick