• Andres Freund's avatar
    Fix ON CONFLICT UPDATE bug breaking AFTER UPDATE triggers. · 84ac126e
    Andres Freund authored
    ExecOnConflictUpdate() passed t_ctid of the to-be-updated tuple to
    ExecUpdate(). That's problematic primarily because of two reason: First
    and foremost t_ctid could point to a different tuple. Secondly, and
    that's what triggered the complaint by Stanislav, t_ctid is changed by
    heap_update() to point to the new tuple version.  The behavior of AFTER
    UPDATE triggers was therefore broken, with NEW.* and OLD.* tuples
    spuriously identical within AFTER UPDATE triggers.
    
    To fix both issues, pass a pointer to t_self of a on-stack HeapTuple
    instead.
    
    Fixing this bug lead to one change in regression tests, which previously
    failed due to the first issue mentioned above. There's a reasonable
    expectation that test fails, as it updates one row repeatedly within one
    INSERT ... ON CONFLICT statement. That is only possible if the second
    update is triggered via ON CONFLICT ... SET, ON CONFLICT ... WHERE, or
    by a WITH CHECK expression, as those are executed after
    ExecOnConflictUpdate() does a visibility check. That could easily be
    prohibited, but given it's allowed for plain UPDATEs and a rare corner
    case, it doesn't seem worthwhile.
    
    Reported-By: Stanislav Grozev
    Author: Andres Freund and Peter Geoghegan
    Discussion: CAA78GVqy1+LisN-8DygekD_Ldfy=BJLarSpjGhytOsgkpMavfQ@mail.gmail.com
    Backpatch: 9.5, where ON CONFLICT was introduced
    84ac126e
triggers.out 69 KB