I was working on a set of triggers in PostgreSQL and I think I stumbled on a bug on the built-in function/trigger suppress_redundant_updates_trigger()
. It's fully reproducible on my configuration (PostgreSQL 12 on my laptop).
First I set up a table, with two "before each row" triggers:
CREATE TABLE test (id int, val text);
INSERT INTO test VALUES (1, 'one'), (2, 'two');
CREATE OR REPLACE FUNCTION am_i_touched() RETURNS trigger LANGUAGE 'plpgsql'
AS $BODY$
BEGIN
RAISE NOTICE 'Yes, I am touched!';
RETURN NEW;
END;
$BODY$;
CREATE TRIGGER az_test_suppress_redundant_update
BEFORE UPDATE ON public.test
FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
-- Make sure trigger name is after the previous one
-- in alphabetical order as it drives execution order
CREATE TRIGGER bz_am_I_touched
BEFORE UPDATE ON public.test
FOR EACH ROW EXECUTE PROCEDURE am_i_touched();
I then run UPDATE test SET id = 1 WHERE id = 1
. As expected, the update is suppressed by the first trigger since the row is left unchanged, and bz_am_i_touched()
never fires. So far so good.
But then I run:
ALTER TABLE test ADD COLUMN newcol int
Now, I run again UPDATE test SET id = 1 WHERE id = 1
... And this time, the update is NOT suppressed and bz_am_i_touched()
fires! PGAdmin (v4) reports that one record was updated, not zero like the time before!
This is a one-off occurrence. Further UPDATE test SET id = 1 WHERE id = 1
work as expected... But then I tried UPDATE test SET id = 2 WHERE id = 2
... and again I have this strange behavior - the update is not suppressed.
Is that an expected behavior? I can't understand how UPDATE test SET id = 1 WHERE id = 1
can result in the update not being suppressed.