postgres.git / summary / log / commit / refs

commit    8c848cd4b8e9e0fee33eaad33cb44376b9e5b480
Author:   Alvaro Herrera <alvherre@alvh.no-ip.org>
Date:     Fri Sep 09 10:22:20 2022 +0000
First released in: 16.0, 15.0

    Fix GetForeignKey*Triggers for self-referential FKs
    
    Because of inadequate filtering, the check triggers were confusing the
    search for action triggers in GetForeignKeyActionTriggers and vice-versa
    in GetForeignKeyCheckTriggers; this confusion results in seemingly
    random assertion failures, and can have real impact in non-asserting
    builds depending on catalog order.  Change these functions so that they
    correctly ignore triggers that are not relevant to each side.
    
    To reduce the odds of further problems, do not break out of the
    searching loop in assertion builds.  This break is likely to hide bugs;
    without it, we would have detected this bug immediately.
    
    This problem was introduced by f4566345cf40, so backpatch to 15 where
    that commit first appeared.
    
    Author: Amit Langote <amitlangote09@gmail.com>
    Discussion: https://postgr.es/m/20220908172029.sejft2ppckbo6oh5@awork3.anarazel.de
    Discussion: https://postgr.es/m/4104619.1662663056@sss.pgh.pa.us


src/backend/commands/tablecmds.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 53b0f3a9c1e..e3233a8f385 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -10581,6 +10581,9 @@ GetForeignKeyActionTriggers(Relation trigrel, continue; if (trgform->tgrelid != confrelid) continue; + /* Only ever look at "action" triggers on the PK side. */ + if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_PK) + continue; if (TRIGGER_FOR_DELETE(trgform->tgtype)) { Assert(*deleteTriggerOid == InvalidOid); @@ -10591,8 +10594,11 @@ GetForeignKeyActionTriggers(Relation trigrel, Assert(*updateTriggerOid == InvalidOid); *updateTriggerOid = trgform->oid; } +#ifndef USE_ASSERT_CHECKING + /* In an assert-enabled build, continue looking to find duplicates */ if (OidIsValid(*deleteTriggerOid) && OidIsValid(*updateTriggerOid)) break; +#endif } if (!OidIsValid(*deleteTriggerOid)) @@ -10636,6 +10642,9 @@ GetForeignKeyCheckTriggers(Relation trigrel, continue; if (trgform->tgrelid != conrelid) continue; + /* Only ever look at "check" triggers on the FK side. */ + if (RI_FKey_trigger_type(trgform->tgfoid) != RI_TRIGGER_FK) + continue; if (TRIGGER_FOR_INSERT(trgform->tgtype)) { Assert(*insertTriggerOid == InvalidOid); @@ -10646,8 +10655,11 @@ GetForeignKeyCheckTriggers(Relation trigrel, Assert(*updateTriggerOid == InvalidOid); *updateTriggerOid = trgform->oid; } +#ifndef USE_ASSERT_CHECKING + /* In an assert-enabled build, continue looking to find duplicates. */ if (OidIsValid(*insertTriggerOid) && OidIsValid(*updateTriggerOid)) break; +#endif } if (!OidIsValid(*insertTriggerOid)) [parent: 8b878bffa8d8]