Обсуждение: IMMEDIATE constraint enforcement does not comply with the SQLstandard

Поиск
Список
Период
Сортировка

IMMEDIATE constraint enforcement does not comply with the SQLstandard

От
"Finnerty, Jim"
Дата:

Problem Description:

 

The current implementation of immediate-mode foreign key constraints in PostgreSQL does not comply with the SQL standard.  According to the standard, an immediate-mode foreign key constraint must be enforced immediately upon statement completion.  This implies that an immediate-mode constraint must be enforced before any ‘after statement’ triggers are fired. 

Foreign Key Constraints in PostgreSQL are implemented as triggers. When a user creates a foreign key constraint, internally the system creates 4 triggers:

·         An after trigger on update of an entry in the foreign key table to check that the constraint is met by the update.

·         An after trigger on insert into the foreign key table to check that the constraint is met by the insert.

·         An after trigger on delete of an entry in the primary key table to check that the constraint is not broken by the delete.

·         An after trigger on update of an entry in the primary key table to check that the constraint is not broken by the update.

 

·         Each of these triggers is given a name that starts with "RI_ConstraintTrigger".

 

PostgreSQL executes AFTER triggers (and constraints) in alphabetical order according to the name assigned to the trigger at creation time; therefore, PostgreSQL permits IMMEDIATE foreign key constraints to be deferred until after AFTER triggers are fired if their name sorts lower than “RI_ConstraintTrigger”.  This is a violation of the standard.

If an AFTER trigger or user-mode constraint has a name (such as “A_trig”) that causes it to fire before an IMMEDIATE foreign key constraint, then arbitrary code can be executed while the constraint is violated, including code that causes the foreign key condition to be satisfied again. In that case the statement should fail according to the standard but it will succeed in PostgreSQL. A user that wants to have code fire before the constraint is enforced can (and should) do so in a standard-compliant way by making the constraint DEFERRABLE INITIALLY DEFERRED.

We believe that the scenario of having a trigger intentionally fixing up an immediate-mode foreign key constraint probably doesn’t happen very often.  This is fortunate, because it makes it possible to conform with the SQL standard without affecting a large number of applications.  What is desired is a solution that preserves the name ordering of triggers, except for the IMMEDIATE constraints, which must fire first.  User-defined IMMEDIATE constraints are not covered by the standard, but we believe that the interpretation most consistent with both the standard and existing PostgreSQL behavior is:

·         Fire the IMMEDIATE system constraint triggers in ascending name order,

·         Then fire the IMMEDIATE user-defined constraint triggers in ascending name order, 

·         Then fire all other triggers in ascending name order

A patch implementing this proposed fix is attached (see after_trigger.diff).

 

Example:

<see fk_bug.sql, attached>

 

postgres=# \i ~/fk_bug.sql

CREATE TABLE

CREATE TABLE

psql:/home/jfinnert/fk_bug.sql:7: ERROR:  insert or update on table "t2" violates foreign key constraint "t2_t1id_fkey"

DETAIL:  Key (t1id)=(1) is not present in table "t1".

CREATE FUNCTION

CREATE TRIGGER

INSERT 0 1

 id |                           data                           

----+----------------------------------------------------------

  1 | the presence of this row in t1 violates the SQL standard

(1 row)

 

 id | t1id |                           data                           

----+------+----------------------------------------------------------

  1 |    1 | the presence of this row in t2 violates the SQL standard

(1 row)

 

 

Platform Information:

 

postgres=# select version();

                                    version                                     

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

 PostgreSQL 10beta3 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.9.3, 64-bit

(1 row)

 

Thank you,

 

    Jim Finnerty, Principal Engineer, Amazon Aurora PostgreSQL

 

Вложения

Re: IMMEDIATE constraint enforcement does not comply with the SQL standard

От
Tom Lane
Дата:
"Finnerty, Jim" <jfinnert@amazon.com> writes:
> PostgreSQL executes AFTER triggers (and constraints) in alphabetical order according to the name assigned to the
triggerat creation time; therefore, PostgreSQL permits IMMEDIATE foreign key constraints to be deferred until after
AFTERtriggers are fired if their name sorts lower than “RI_ConstraintTrigger”.  This is a violation of the standard. 

We consider that a feature, not a bug.  If you want standard-compliant
behavior, don't name your triggers that way.  On the other hand, if
you'd like to get something done before FK constraints fire, you have
the option to do so.

(I think this is documented somewhere.  If not, there's an opportunity
for documentation improvement.)

The fact that the sort is plain ASCII means that "RI_ConstraintTrigger"
sorts before any lower-case trigger name, so the issue is not as large
as it might otherwise seem.

            regards, tom lane


Re: IMMEDIATE constraint enforcement does not comply with the SQL standard

От
Tom Lane
Дата:
"Finnerty, Jim" <jfinnert@amazon.com> writes:
> PostgreSQL executes AFTER triggers (and constraints) in alphabetical order according to the name assigned to the
triggerat creation time; therefore, PostgreSQL permits IMMEDIATE foreign key constraints to be deferred until after
AFTERtriggers are fired if their name sorts lower than “RI_ConstraintTrigger”.  This is a violation of the standard. 

We consider that a feature, not a bug.  If you want standard-compliant
behavior, don't name your triggers that way.  On the other hand, if
you'd like to get something done before FK constraints fire, you have
the option to do so.

(I think this is documented somewhere.  If not, there's an opportunity
for documentation improvement.)

The fact that the sort is plain ASCII means that "RI_ConstraintTrigger"
sorts before any lower-case trigger name, so the issue is not as large
as it might otherwise seem.

            regards, tom lane



Re: IMMEDIATE constraint enforcement does not comply with the SQLstandard

От
Jim Finnerty
Дата:
We do want standard-compliant behavior, and standard-compliance a strength of
PostgreSQL, and as mentioned we already do have a way (DEFERRABLE INITIALLY
DEFERRED) if this is the user's intent.

The consequences of non-compliance is much more insidious than it at first
appears.  At stake here is whether PostgreSQL supports non-deferrable
constraints at all.  The purpose of having non-deferrable IMMEDIATE
constraints in the standard is to make query optimizations possible.  

Also, as far as I can tell, we do not document the specific name that we
generate for constraint triggers; therefore, any application that depends on
undocumented naming conventions is skating on precariously thin ice, in
addition to writing non-portable code.

The equivalent logic was implemented on Oracle and MySQL.  Both of those
systems implement IMMEDIATE mode constraints consistently with the standard,
and produce a different result than PostgreSQL.

best regards,

    /Jim F 



-----
Jim Finnerty, AWS, Amazon Aurora PostgreSQL
--
Sent from: http://www.postgresql-archive.org/PostgreSQL-bugs-f2117394.html


Re: IMMEDIATE constraint enforcement does not comply with the SQLstandard

От
Jim Finnerty
Дата:
We do want standard-compliant behavior, and standard-compliance a strength of
PostgreSQL, and as mentioned we already do have a way (DEFERRABLE INITIALLY
DEFERRED) if this is the user's intent.

The consequences of non-compliance is much more insidious than it at first
appears.  At stake here is whether PostgreSQL supports non-deferrable
constraints at all.  The purpose of having non-deferrable IMMEDIATE
constraints in the standard is to make query optimizations possible.  

Also, as far as I can tell, we do not document the specific name that we
generate for constraint triggers; therefore, any application that depends on
undocumented naming conventions is skating on precariously thin ice, in
addition to writing non-portable code.

The equivalent logic was implemented on Oracle and MySQL.  Both of those
systems implement IMMEDIATE mode constraints consistently with the standard,
and produce a different result than PostgreSQL.

best regards,

    /Jim F 



-----
Jim Finnerty, AWS, Amazon Aurora PostgreSQL
--
Sent from: http://www.postgresql-archive.org/PostgreSQL-bugs-f2117394.html



Re: IMMEDIATE constraint enforcement does not comply with the SQL standard

От
Andrew Gierth
Дата:
>>>>> "Jim" == Jim Finnerty <jfinnert@amazon.com> writes:

 Jim> The consequences of non-compliance is much more insidious than it
 Jim> at first appears. At stake here is whether PostgreSQL supports
 Jim> non-deferrable constraints at all. The purpose of having
 Jim> non-deferrable IMMEDIATE constraints in the standard is to make
 Jim> query optimizations possible.

Unfortunately the possibility of query optimizations for FKs is already
defeated by the issue of referential actions, where we also violate the
spec.

https://wiki.postgresql.org/wiki/PostgreSQL_vs_SQL_Standard#Trigger_firing_relative_to_referential_constraint_actions

(I just added your issue to that entry, which was already there to
discuss the referential actions vs BEFORE trigger timing.)

-- 
Andrew (irc:RhodiumToad)


Re: IMMEDIATE constraint enforcement does not comply with the SQL standard

От
Andrew Gierth
Дата:
>>>>> "Jim" == Jim Finnerty <jfinnert@amazon.com> writes:

 Jim> The consequences of non-compliance is much more insidious than it
 Jim> at first appears. At stake here is whether PostgreSQL supports
 Jim> non-deferrable constraints at all. The purpose of having
 Jim> non-deferrable IMMEDIATE constraints in the standard is to make
 Jim> query optimizations possible.

Unfortunately the possibility of query optimizations for FKs is already
defeated by the issue of referential actions, where we also violate the
spec.

https://wiki.postgresql.org/wiki/PostgreSQL_vs_SQL_Standard#Trigger_firing_relative_to_referential_constraint_actions

(I just added your issue to that entry, which was already there to
discuss the referential actions vs BEFORE trigger timing.)

-- 
Andrew (irc:RhodiumToad)



Re: IMMEDIATE constraint enforcement does not comply with the SQLstandard

От
Jim Finnerty
Дата:
ON [ DELETE | UPDATE ] [ CASCADE | RESTRICT ] pertains to inter-table
relationships.  My understanding is that the constraint trigger names have
been carefully chosen in order to get the referential actions to work
correctly; however, this patch does not change the names or the relative
firing order of constraint triggers relative to each other.

The SET NULL action is not problematic with respect to standard compliance,
but the SET DEFAULT action potentially would be.  According to the
documentation page that you referenced, though:

"... if an action specifies SET DEFAULT but the default value would not
satisfy the foreign key constraint, the operation will fail."

The patch passes all tests in installcheck serial, as well as the tests we
have added (included with the patch), so if there is a problem we don't have
test coverage for it.  Can anyone devise a test that would cause the patch
to change the behavior of a BEFORE trigger or a referential action?

thank you,

    /Jim F



-----
Jim Finnerty, AWS, Amazon Aurora PostgreSQL
--
Sent from: http://www.postgresql-archive.org/PostgreSQL-bugs-f2117394.html


Re: IMMEDIATE constraint enforcement does not comply with the SQLstandard

От
Jim Finnerty
Дата:
We created a repro for the ON UPDATE CASCADE ... BEFORE trigger problem,
which as Andrew said is a second area where the SQL standard is violated.



-----
Jim Finnerty, AWS, Amazon Aurora PostgreSQL
--
Sent from: http://www.postgresql-archive.org/PostgreSQL-bugs-f2117394.html