]> granicus.if.org Git - postgresql/commit
Fix ON CONFLICT UPDATE bug breaking AFTER UPDATE triggers.
authorAndres Freund <andres@anarazel.de>
Thu, 10 Dec 2015 15:26:45 +0000 (16:26 +0100)
committerAndres Freund <andres@anarazel.de>
Thu, 10 Dec 2015 15:29:26 +0000 (16:29 +0100)
commit84ac126ee728ede5b6370d60dd2b1c299f49ed2f
tree912b9096b1c9c17a12a4795b9edef4802dda1198
parente3f4cfc7aa33f40b2b283676c9f0d5bf7ef08ccd
Fix ON CONFLICT UPDATE bug breaking AFTER UPDATE triggers.

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
src/backend/executor/nodeModifyTable.c
src/test/regress/expected/triggers.out
src/test/regress/expected/with.out
src/test/regress/sql/triggers.sql
src/test/regress/sql/with.sql