Reputation: 215
Suppose we have:
create table T
(
id bigserial primary key
, a int
, b int
, c int
);
I want c
to be always equals to a+b
and I want to prevent manual changes of c
. So I create two triggers:
-- Prevents manual changes of c:
create or replace function no_changes() returns trigger as $$
begin
if old.c is distinct from new.c then
raise exception 'Can''t change c manually.';
end if;
return new;
end;
$$ language plpgsql;
create trigger no_changes
before update of c -- 'before' so prevents changes in 'c'
on T
for each row
execute procedure no_changes();
-- Do c = a + b:
create or replace function change() returns trigger as $$
begin
update T
set c = a + b
where id = new.id;
return new;
end;
$$ language plpgsql;
create trigger change
after insert or update of a, b -- 'after' so I'm sure the row is inserted/updated
on T
for each row
execute procedure change();
If I do:
update T set c = 247;
I see the error message "Can't change c manually" and the column doesn't changes. Great.
However, If I do:
insert into T (a, b) values (4, 3);
Or:
update T set a = 3 where id = 2 -- suppose id = 2 exists
Then I get the same error message as before. Obviously, The update
command from change
trigger fires no_changes
trigger preventing the update in the c
column.
Any ideas? Thanks!
Upvotes: 3
Views: 75
Reputation: 15614
The whole logic could be placed in single function:
create or replace function change() returns trigger as $$
begin
if old.c is distinct from new.c then
raise exception 'Can''t change c manually.';
end if;
new.c := new.a + new.b;
return new;
end;
$$ language plpgsql;
create trigger change
before insert or update on T
for each row
execute procedure change();
But if you prefer to split the logic, then
1) Create both triggers on before
event
2) "If multiple triggers of the same kind are defined for the same event, they will be fired in alphabetical order by name." So name triggers to get the desired order, for example trg1_check
to prevent changes of c
and trg2_change
to calculate c
value.
Upvotes: 4