❖ 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 INSERT
DELETE
UPDATE
FOR EACH ROW
COMMIT
❖ Trigger Semantics |
Triggers can be activated BEFORE
AFTER
If activated BEFORE
NEW
NEW
AFTER
NEW
OLD
NEW
OLD
NEW
❖ 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:
Code1
X
(a,b,c,...)
NEW
a,b,c,..
a,b,c,..
NEW
NEW
Code2
Y
NEW
OLD
INSERT
❖ 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:
Code1
X
OLD
NEW
b,c,..
a,b,c,..
NEW
NEW
OLD
Code2
Y
NEW
OLD
NEW
❖ 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:
Code1
X
(a,b,c,...)
OLD
a,b,c,..
OLD
OLD
Code2
Y
OLD
NEW
❖ Triggers in PostgreSQL |
PostgreSQL triggers provide a mechanism for
INSERT
DELETE
UPDATE
TriggerName { CREATE TRIGGER
| AFTER
} Event1 [ BEFORE
Event2 ...] OR
TableName [ ON
( Condition ) ] WHEN
{ROW|STATEMENT} FOR EACH
FunctionName(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 BEFORE
OLD
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