PostgreSQL trigger prevents another from running

Let's pretend that:

create table T
(
    id bigserial primary key
  , a  int
  , b  int
  , c  int
);

      

I want to c

always equal a+b

and I want to prevent manual changes c

. Therefore, 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 this:

update T set c = 247;

      

I see the error "Cannot manually change c" and the column does not change. Fine.

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 command update

from change

invokes the trigger no_changes

, preventing the column from being updated c

.

Any ideas? Thank!

+3


source to share


1 answer


All logic can be put into one 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 separate the logic, then
1) Create both triggers on the event before


2) "If multiple triggers of the same type are defined for the same event, they will be fired in alphabetical order by name." So the name triggers to get the desired order, for example trg1_check

, to prevent changes c

and trg2_change

to calculate the value c

.

+4


source







All Articles