In Postgres 9.0 or later add a WHEN
clause to your trigger definition (CREATE TRIGGER
statement):
CREATE TRIGGER foo
BEFORE UPDATE
FOR EACH ROW
WHEN (OLD IS DISTINCT FROM NEW) -- parentheses required!
EXECUTE PROCEDURE ...;
Only possible for triggers BEFORE
/ AFTER
UPDATE
, where both OLD
and NEW
are defined. You'd get an exception trying to use this WHEN
clause with INSERT
or DELETE
triggers.
And radically simplify the trigger function accordingly:
...
IF OLD.locked > 0 THEN
RAISE EXCEPTION 'Message';
END IF;
...
No need to test IF TG_OP='UPDATE' ...
since this trigger only works for UPDATE
anyway.
Or move that condition in the WHEN clause, too:
CREATE TRIGGER foo
BEFORE UPDATE
FOR EACH ROW
WHEN (OLD.locked > 0
AND OLD IS DISTINCT FROM NEW)
EXECUTE PROCEDURE ...;
Leaving only an unconditional RAISE EXCEPTION
in your trigger function, which is only called when needed to begin with.
Read the fine print:
In a BEFORE
trigger, the WHEN
condition is evaluated just before the
function is or would be executed, so using WHEN
is not materially
different from testing the same condition at the beginning of the
trigger function. Note in particular that the NEW
row seen by the
condition is the current value, as possibly modified by earlier
triggers. Also, a BEFORE
trigger's WHEN
condition is not allowed to
examine the system columns of the NEW
row (such as oid
), because those
won't have been set yet.
In an AFTER
trigger, the WHEN
condition is evaluated just after the
row update occurs, and it determines whether an event is queued to
fire the trigger at the end of statement. So when an AFTER
trigger's
WHEN
condition does not return true, it is not necessary to queue an
event nor to re-fetch the row at end of statement. This can result in
significant speedups in statements that modify many rows, if the
trigger only needs to be fired for a few of the rows.
Related:
To also address the question title
Is it possible to dynamically loop through a table's columns?
Yes. Examples: