❖ Triggers |
Triggers are
❖ Triggers (cont) |
Triggers provide event-condition-action (ECA) programming:
❖ Triggers (cont) |
SQL "standard" syntax for defining triggers:
CREATE TRIGGER TriggerName
{AFTER|BEFORE} Event1 [ OR Event2 ... ]
[ FOR EACH ROW ]
ON TableName
[ WHEN ( Condition ) ]
Block of Procedural/SQL Code ;
Possible Events are INSERTDELETEUPDATE
FOR EACH ROW
COMMIT❖ Trigger Semantics |
Triggers can be activated BEFOREAFTER
If activated BEFORE
NEWNEWAFTERNEWOLDNEWOLDNEW❖ Trigger Semantics (cont) |
Sequence of activities during database update:
Reminder: BEFORE
❖ Trigger Semantics (cont) |
Consider two triggers and an INSERT statement
create trigger X before insert on T Code1; create trigger Y after insert on T Code2; insert into T values (a,b,c,...);
Sequence of events:
Code1X(a,b,c,...)NEWa,b,c,..a,b,c,..NEWNEWCode2YNEWOLDINSERT❖ Trigger Semantics (cont) |
Consider two triggers and an UPDATE statement
create trigger X before update on T Code1; create trigger Y after update on T Code2; update T set b=j,c=k where a=m;
Sequence of events:
Code1XOLDNEWb,c,..a,b,c,..NEWNEWOLDCode2YNEWOLDNEW❖ Trigger Semantics (cont) |
Consider two triggers and an DELETE statement
create trigger X before delete on T Code1; create trigger Y after delete on T Code2; delete from T where a=m;
Sequence of events:
Code1X(a,b,c,...)OLDa,b,c,..OLDOLDCode2YOLDNEW❖ Triggers in PostgreSQL |
PostgreSQL triggers provide a mechanism for
INSERTDELETEUPDATETriggerName { CREATE TRIGGER| AFTER} Event1 [ BEFOREEvent2 ...] ORTableName [ ON( Condition ) ] WHEN{ROW|STATEMENT} FOR EACHFunctionName(args...); EXECUTE PROCEDURE
❖ Triggers in PostgreSQL (cont) |
There is no restriction on what code can go in the function.
However a BEFORE
RETURN old; or RETURN new;
depending on which version of the tuple is to be used.
It can also return NULL
If BEFOREOLD
If exception is raised in trigger function, no change occurs.
❖ Trigger Example #1 |
Consider a database of people in the USA:
create table Person ( id integer primary key, ssn varchar(11) unique, ... e.g. family, given, street, town ... state char(2), ... ); create table States ( id integer primary key, code char(2) unique, ... e.g. name, area, population, flag ... );
Constraint: Person.state(select code from States)
exists (select id from States where code=Person.state)
❖ Trigger Example #1 (cont) |
Example: ensure that only valid state codes are used:
create trigger checkState before insert or update on Person for each row execute procedure checkState(); create function checkState() returns trigger as $$ begin -- normalise the user-supplied value new.state = upper(trim(new.state)); if (new.state !~ '^[A-Z][A-Z]$') then raise exception 'Code must be two alpha chars'; end if; -- implement referential integrity check select * from States where code=new.state; if (not found) then raise exception 'Invalid code %',new.state; end if; return new; end; $$ language plpgsql;
❖ Trigger Example #1 (cont) |
Examples of how this trigger would behave:
insert into Person
values('John',...,'Calif.',...);
-- fails with 'Statecode must be two alpha chars'
insert into Person
values('Jane',...,'NY',...);
-- insert succeeds; Jane lives in New York
update Person
set town='Sunnyvale',state='CA'
where name='Dave';
-- update succeeds; Dave moves to California
update Person
set state='OZ' where name='Pete';
-- fails with 'Invalid state code OZ'
❖ Trigger Example #2 |
Example: department salary totals
Scenario:
Employee(id, name, address, dept, salary, ...) Department(id, name, manager, totSal, ...)
An assertion that we wish to maintain:
create assertion TotalSalary check (
not exists (
select * from Department d
where d.totSal <> (select sum(e.salary)
from Employee e
where e.dept = d.id)
)
)
❖ Trigger Example #2 (cont) |
Events that might affect the validity of the database
With triggers, we have to program each case separately.
Each program implements updates to ensure assertion holds.
❖ Trigger Example #2 (cont) |
Implement the Employee update triggers from above in PostgreSQL:
Case 1: new employees arrive
create trigger TotalSalary1
after insert on Employees
for each row execute procedure totalSalary1();
create function totalSalary1() returns trigger
as $$
begin
if (new.dept is not null) then
update Department
set totSal = totSal + new.salary
where Department.id = new.dept;
end if;
return new;
end;
$$ language plpgsql;
❖ Trigger Example #2 (cont) |
Case 2: employees change departments/salaries
create trigger TotalSalary2
after update on Employee
for each row execute procedure totalSalary2();
create function totalSalary2() returns trigger
as $$
begin
update Department
set totSal = totSal + new.salary
where Department.id = new.dept;
update Department
set totSal = totSal - old.salary
where Department.id = old.dept;
return new;
end;
$$ language plpgsql;
❖ Trigger Example #2 (cont) |
Case 3: employees leave
create trigger TotalSalary3
after delete on Employee
for each row execute procedure totalSalary3();
create function totalSalary3() returns trigger
as $$
begin
if (old.dept is not null) then
update Department
set totSal = totSal - old.salary
where Department.id = old.dept;
end if;
return old;
end;
$$ language plpgsql;
Produced: 26 Oct 2021