Déclencheur base de données

Transcription

Déclencheur base de données
Déclencheurs Bases de
Données
TRIGGER
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI
Généralités
•• Un
Un déclencheur
déclencheur est
est un
un traitement
traitement (sous
(sous
forme
forme de
de bloc
bloc PL/SQL)
PL/SQL) qui
qui s’exécute
s’exécute
automatiquement
automatiquement en
en réponse
réponse àà un
un
événement.
événement.
•• Deux
Deux types
types ::
–– Déclencheur
Déclencheur base
base de
de données
données
–– Déclencheur
Déclencheur d’application
d’application
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 2
Déclencheur Base de Données
Exemple
Application
SQL>
SQL>
22
INSERT
INSERT INTO
INTO EMP
EMP
.. .. .;
.;
EMP table
EMPNO
7838
7698
7369
7788
ENAME
KING
BLAKE
SMITH
SCOTT
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
CHECK_SAL trigger
JOB
PRESIDENT
MANAGER
CLERK
ANALYST
SAL
5000
2850
800
3000
Cours PL/SQL d’après cours ORACLE - OAI / 3
Création d’un déclencheur
•• Synchronisation
Synchronisation :: BEFORE
BEFORE ou
ou AFTER
AFTER
ou
ou INSTEAD
INSTEAD OF
OF
•• Événement
Événement :: INSERT
INSERT ou
ou UPDATE
UPDATE ou
ou
DELETE
DELETE
•• Nom
Nom Table
Table :: On
On table
table
•• Type:
Type: Ligne(Row)
Ligne(Row) ou
ou ordre
ordre SQL
SQL
•• Condition
Condition restrictive
restrictive :: Clause
Clause When
When
•• Traitement
Traitement associé
associé :: Bloc
Bloc PL/SQL
PL/SQL
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 4
Élément d’un déclencheur
Synchronisation :
•• BEFORE
BEFORE :: Le
Le traitement
traitement est
est exécuté
exécuté
avant
avant l’ordre
l’ordre LMD
LMD qui
qui l’a
l’a déclenché.
déclenché.
•• AFTER
AFTER :: Le
Le traitement
traitement est
est exécuté
exécuté après
après
l’ordre
l’ordre LMD
LMD qui
qui l’a
l’a déclenché.
déclenché.
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 5
Élément d’un déclencheur
Synchronisation :
•• INSTEAD
INSTEAD OF:
OF: Le
Le traitement
traitement est
est exécuté
exécuté
en
en lieu
lieu et
et place
place de
de l’exécution
l’exécution de
de l’ordre
l’ordre
LMD
LMD qui
qui l’a
l’a déclenché.
déclenché.
•• Utilisée
Utilisée pour
pour faire
faire des
des mises
mises àà jour
jour
"à
"à travers"
travers" des
des VUES.
VUES.
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 6
Élément d’un déclencheur
É
vénement::
Événement
•• Indique
Indique quel
quel ordre
ordre SQL
SQL déclenche
déclenche le
le
traitement
traitement ::
–– INSERT
INSERT
–– UPDATE
UPDATE
–– DELETE
DELETE
–– Toute
Toute combinaison
combinaison de
de ces
ces ordres
ordres
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 7
Élément d’un déclencheur
Type ::
Combien
Combien de
de fois
fois le
le traitement
traitement doit
doit
s'ex
écuter suite
événement qui
s'exécuter
suite àà l'l'événement
qui l'a
l'a
d
éclenché ?
déclenché
?
•• ORDRE
ORDRE :: Le
Le traitement
traitement est
est exécuté
exécuté une
une
seule
seule fois.
fois.
–– Option
Option par
par défaut.
défaut.
•• Ligne
Ligne (Row)
(Row) :: Le
Le traitement
traitement est
est exécuté
exécuté
pour
pour chaque
chaque ligne
ligne affectée
affectée par
par
l'événement.
l'événement.
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 8
Élément d’un déclencheur
Traitement - corps du d
éclencheur :
déclencheur
Quelle
écuter ?
Quelle action
action àà ex
exécuter
?
•• Le
Le corps
corps du
du déclencheur
déclencheur est
est défini
défini sous
sous
forme
forme d'un
d'un bloc
bloc PL/SQL
PL/SQL anonyme.
anonyme.
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 9
Déclencheur ordre et ligne
Example
SQL>
SQL>
22
33
UPDATE
UPDATE emp
emp
SET
SET sal
sal == sal
sal ** 1.1
1.1
WHERE
WHERE deptno
deptno == 30;
30;
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 10
Synchronisation du déclencheur
BEFORE ordre
EMPNO
ENAME
7839
KING
30
7698
BLAKE
30
7788
SMITH
30
DEPTNO
BEFORE ligne
AFTER ligne
BEFORE ligne
AFTER ligne
BEFORE ligne
AFTER ligne
AFTER ordre
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 11
Création d'un déclencheur
ORDRE
CREATE
CREATE [OR
[OR REPLACE]
REPLACE] TRIGGER
TRIGGER nom_déclencheur
nom_déclencheur
positionnement
positionnement événement
événement [OR
[OR événement
événement OR
OR ...]
...]
ON
ON Nom_table
Nom_table
PL/SQL
PL/SQL block;
block;
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 12
Exemple : Déclencheur BEFORE
SQL>
SQL>
22
33
44
55
66
77
88
CREATE
CREATE OR
OR REPLACE
REPLACE TRIGGER
TRIGGER secure_emp
secure_emp
BEFORE
BEFORE INSERT
INSERT ON
ON emp
emp
BEGIN
BEGIN
IF
IF (TO_CHAR
(TO_CHAR (sysdate,'DY')
(sysdate,'DY') IN
IN ('SAT','SUN'))
('SAT','SUN'))
OR
OR (TO_CHAR(sysdate,'HH24')NOT
(TO_CHAR(sysdate,'HH24')NOT BETWEEN
BETWEEN
'08'
'08' AND
AND '18'
'18'
THEN
THEN RAISE_APPLICATION_ERROR
RAISE_APPLICATION_ERROR (-20500,
(-20500,
'Vous
'Vous ne
ne pouvez
pouvez utiliser
utiliser la
la table
table EMP
EMP
que
que pendant
pendant les
les heures
heures normales.');
normales.');
10
END
10
END IF;
IF;
11
11 END;
END;
12
12 //
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 13
Exemple (suite)
SQL>
SQL>
22
INSERT
INSERT INTO
INTO emp
emp (empno,
(empno, ename,
ename, deptno)
deptno)
VALUES
(7777,
VALUES
(7777, 'BAUWENS',
'BAUWENS', 40);
40);
INSERT
INSERT INTO
INTO emp
emp (empno,
(empno, ename,
ename, deptno)
deptno)
**
ERROR
ERROR at
at line
line 1:
1:
ORA-20500:
ORA-20500: 'Vous
'Vous ne
ne pouvez
pouvez utiliser
utiliser la
la table
table EMP
EMP
que
que pendant
pendant les
les heures
heures normales.
normales.
ORA-06512:
ORA-06512:
ORA-04088:
ORA-04088:
at
at "SCOTT.SECURE_EMP",
"SCOTT.SECURE_EMP",
error
error during
during execution
execution
line
line 44
of
of trigger
trigger
'SCOTT.SECURE_EMP'
'SCOTT.SECURE_EMP'
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 14
Conditions sur l'événement
SQL>CREATE
SQL>CREATE OR
OR REPLACE
REPLACE TRIGGER
TRIGGER secure_emp
secure_emp
22 BEFORE
INSERT
OR
UPDATE
OR
BEFORE INSERT OR UPDATE OR DELETE
DELETE ON
ON emp
emp
33 BEGIN
BEGIN
44 IF
IF(TO_CHAR
(TO_CHAR (sysdate,'DY')
(sysdate,'DY') IN
IN ('SAT','SUN'))
('SAT','SUN')) OR
OR
55 (TO_CHAR
(TO_CHAR (sysdate,
(sysdate, 'HH24')
'HH24') NOT
NOT BETWEEN
BETWEEN '08'
'08' AND
AND '18')
'18') THEN
THEN
66
IF
DELETING
THEN
IF DELETING THEN
77
RAISE_APPLICATION_ERROR
RAISE_APPLICATION_ERROR (-20502,
(-20502,
88
'Suppression
'Suppression impossible
impossible àà cette
cette heure
heure.');
.');
99
ELSIF
INSERTING
THEN
ELSIF INSERTING THEN
10
RAISE_APPLICATION_ERROR
10
RAISE_APPLICATION_ERROR (-20500,
(-20500,
11
'Création
11
'Création impossible
impossible àà cette
cette heure
heure.');
.');
12
ELSIF
UPDATING
('SAL')
THEN
12
ELSIF UPDATING ('SAL') THEN
13
RAISE_APPLICATION_ERROR
13
RAISE_APPLICATION_ERROR (-20503,
(-20503,
14
'Modification
14
'Modification impossible
impossible àà cette
cette heure
heure.');
.');
15
ELSE
15
ELSE
16
RAISE_APPLICATION_ERROR
16
RAISE_APPLICATION_ERROR (-20504,
(-20504,
17
'Mises
17
'Mises àà jour
jour impossibles
impossibles àà cette
cette heure.');
heure.');
18
END
18
END IF;
IF;
19
19 END
END IF;
IF;
20
END;
20 END;
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 15
Exemple : Déclencheur AFTER
SQL>CREATE
SQL>CREATE OR
OR REPLACE
REPLACE TRIGGER
TRIGGER check_salary_count
check_salary_count
22 AFTER
AFTER UPDATE
UPDATE OF
OF sal
sal ON
ON emp
emp
33 DECLARE
DECLARE
44 v_salary_changes
v_salary_changes NUMBER;
NUMBER;
55 v_max_changes
NUMBER;
v_max_changes
NUMBER;
66 BEGIN
BEGIN
77 SELECT
SELECT upd,
upd, max_upd
max_upd
88 INTO
v_salary_changes,
INTO
v_salary_changes, v_max_changes
v_max_changes
99 FROM
audit_table
FROM
audit_table
10
10 WHERE
WHERE user_name
user_name == user
user
11
table_name
11 AND
AND
table_name == 'EMP'
'EMP'
12
column_name
12 AND
AND
column_name == 'SAL';
'SAL';
13
IF
v_salary_changes
>
13
IF v_salary_changes > v_max_changes
v_max_changes THEN
THEN
14
RAISE_APPLICATION_ERROR
(-20501,
14
RAISE_APPLICATION_ERROR (-20501,
15
'Respectez
15
'Respectez le
le maximum
maximum :: '||
'||
16
TO_CHAR
16
TO_CHAR (v_max_changes)
(v_max_changes) ||
||
17
'' admissible
17
admissible pour
pour le
le salaire');
salaire');
18
18 END
END IF;
IF;
19
END;
19 END;
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 16
Utilisation d'une table d'AUDIT
USER_NAME
SCOTT
SCOTT
JONES
TABLENAME
EMP
EMP
EMP
COLUMN_NAME
INS
1
SAL
0
UPD
1
1
0
DEL
1
0
...
MAX_INS
5
5
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
MAX_UPD
5
5
0
Cours PL/SQL d’après cours ORACLE - OAI / 17
MAX_DEL
5
0
Création d'un déclencheur
LIGNE
CREATE
CREATE [OR
[OR REPLACE]
REPLACE] TRIGGER
TRIGGER nom_déclencheur
nom_déclencheur
positionnement
positionnement événement
événement [OR
[OR événement
événement OR
OR ...]
...]
ON
ON nom_table
nom_table
[REFERENCING
[REFERENCING OLD
OLD AS
AS old
old || NEW
NEW AS
AS new]
new]
FOR
FOR EACH
EACH ROW
ROW
[WHEN
[WHEN condition]
condition]
PL/SQL
PL/SQL block;
block;
OLD
OLD :: avant
avant exécution
exécution de
de l'ordre
l'ordre LMD
LMD
NEW
NEW :: après
après exécution
exécution de
de l'ordre
l'ordre LMD
LMD
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 18
Déclencheur AFTER : Exemple
SQL>CREATE
SQL>CREATE OR
OR REPLACE
REPLACE TRIGGER
TRIGGER audit_emp
audit_emp
22 AFTER
DELETE
OR
INSERT
OR
UPDATE
AFTER DELETE OR INSERT OR UPDATE ON
ON emp
emp
33 FOR
EACH
ROW
FOR EACH ROW
44 BEGIN
BEGIN
55 IF
IF DELETING
DELETING THEN
THEN
66
UPDATE
audit_table
UPDATE audit_table SET
SET del
del == del
del ++ 11
77
WHERE
WHERE user_name
user_name == user
user AND
AND table_name
table_name == 'EMP'
'EMP'
88
AND
column_name
IS
NULL;
AND
column_name IS NULL;
99 ELSIF
INSERTING
ELSIF INSERTING THEN
THEN
10
UPDATE
audit_table
10
UPDATE audit_table SET
SET ins
ins == ins
ins ++ 11
11
WHERE
11
WHERE user_name
user_name == user
user AND
AND table_name
table_name == 'EMP'
'EMP'
12
AND
column_name
IS
NULL;
12
AND
column_name IS NULL;
13
ELSIF
UPDATING
13 ELSIF UPDATING ('SAL')
('SAL') THEN
THEN
14
UPDATE
audit_table
SET
14
UPDATE audit_table SET upd
upd == upd
upd ++ 11
15
WHERE
15
WHERE user_name
user_name == user
user AND
AND table_name
table_name == 'EMP'
'EMP'
16
AND
column_name
=
'SAL';
16
AND
column_name = 'SAL';
17
ELSE
/*
The
17 ELSE /* The data
data manipulation
manipulation operation
operation is
is aa general
general UPDATE.
UPDATE. */
*/
18
UPDATE
audit_table
SET
upd
=
upd
+
1
18
UPDATE audit_table SET upd = upd + 1
19
WHERE
19
WHERE user_name
user_name == user
user AND
AND table_name
table_name == 'EMP'
'EMP'
20
AND
column_name
IS
NULL;
20
AND
column_name IS NULL;
21
END
IF;
21 END IF;
22
22 END;
END;
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 19
Utilisation des valeurs
avant et après
SQL>CREATE
SQL>CREATE OR
OR REPLACE
REPLACE TRIGGER
TRIGGER audit_emp_values
audit_emp_values
22 AFTER
AFTER DELETE
DELETE OR
OR INSERT
INSERT OR
OR UPDATE
UPDATE ON
ON emp
emp
33 FOR
FOR EACH
EACH ROW
ROW
44 BEGIN
BEGIN
55
INSERT
INSERT INTO
INTO audit_emp_values
audit_emp_values (user_name,
(user_name,
66
timestamp,
timestamp, id,
id, old_last_name,
old_last_name, new_last_name,
new_last_name,
77
old_title,
old_title, new_title,
new_title, old_salary,
old_salary, new_salary)
new_salary)
88
VALUES
VALUES (USER,
(USER, SYSDATE,
SYSDATE, :old.empno,
:old.empno, :old.ename,
:old.ename,
99
:new.ename,
:new.ename, :old.job,
:old.job, :new.job,
:new.job,
10
:old.sal,
10
:old.sal, :new.sal);
:new.sal);
11
11 END;
END;
12
12 //
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 20
Utilisation de la table
Audit_Emp_Values
USER_NAME
EGRAVINA
TIMESTAMP
12-NOV-97
ID OLD_LAST_NAME NEW_LAST_NAME
HUTTON
7950 NULL
NGREENBE
10-DEC-97
7844 MAGEE
TURNER
...
OLD_TITLE
NULL
NEW_TITLE
ANALYST
CLERK
SALESMAN
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
OLD_SALARY
NULL
NEW_SALARY
3500
1100
1100
Cours PL/SQL d’après cours ORACLE - OAI / 21
Restriction déclencheur LIGNE
Clause WHEN
SQL>CREATE
SQL>CREATE OR
OR REPLACE
REPLACE TRIGGER
TRIGGER derive_commission_pct
derive_commission_pct
22 BEFORE
BEFORE INSERT
INSERT OR
OR UPDATE
UPDATE OF
OF sal
sal ON
ON emp
emp
33 FOR
FOR EACH
EACH ROW
ROW
44 WHEN
WHEN (new.job
(new.job == 'SALESMAN')
'SALESMAN')
55 BEGIN
BEGIN
66 IF
IF INSERTING
INSERTING THEN
THEN :new.comm
:new.comm :=
:= 0;
0;
77
ELSE
/*
ELSE
/* UPDATE
UPDATE of
of salary
salary */
*/
88
IF
IF :old.comm
:old.comm IS
IS NULL
NULL THEN
THEN
99
:new.comm
:new.comm :=0;
:=0;
10
ELSE
10
ELSE
11
:new.comm
11
:new.comm :=
:= :old.comm
:old.comm ** (:new.sal/:old.sal);
(:new.sal/:old.sal);
12
END
12
END IF;
IF;
13
13 END
END IF;
IF;
14
14 END;
END;
15
15 //
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 22
Déclencheur ou Procédure
Stockée
Déclencheur
Procédure
CREATE TRIGGER
CREATE PROCEDURE
Code source et p-code dans le
dictionnaire de la base
Code source et p-code dans
le dictionnaire de la base
Appel implicite
Appel explicite
COMMIT, SAVEPOINT,
ROLLBACK non autorisés
COMMIT, SAVEPOINT,
ROLLBACK autorisés
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 23
Gestion des Déclencheurs
Activation / désactivation d'un seul déclencheur
ALTER
ALTER TRIGGER
TRIGGER nom_déclencheur
nom_déclencheur DISABLE
DISABLE || ENABLE;
ENABLE;
Activation / désactivation de tous les
déclencheurs associés à une table
ALTER
ALTER TABLE
TABLE nom_table
nom_table DISABLE
DISABLE || ENABLE
ENABLE ALL
ALL TRIGGERS;
TRIGGERS;
Recompilation d’un déclencheur
ALTER
ALTER TRIGGER
TRIGGER trigger_name
trigger_name COMPILE;
COMPILE;
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 24
Suppression d'un Déclencheur
DROP
DROP TRIGGER
TRIGGER ::
DROP
DROP TRIGGER
TRIGGER nom_déclencheur;
nom_déclencheur;
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 25
Règles d'utilisation des
Déclencheurs Ligne
•• Règle
Règle 1:
1: Ne
Ne pas
pas modifier
modifier les
les données
données
des
des colonnes
colonnes définies
définies comme
comme ::
primary
primary key,
key, foreign
foreign key,
key, ou
ou
unique
unique key
key d’une
d’une table
table liée.
liée.
•• Règle
Règle 2:
2: Ne
Ne pas
pas accéder
accéder aux
aux données
données
d'une
d'une table
table en
en mise
mise àà jour
jour
(«
(« mutating
mutating »» table).
table).
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 26
Déclencheur et Tables Liées (1)
évènement
SQL>
SQL>
22
33
Traitement
EMP table
EMPNO ENAME
7698 BLAKE
7654 MARTIN
7499 ALLEN
Table liée
Intégrité référentielle
DEPTNO
DEPTNO
30
30
30
Erreur
10
20
30
40
DEPT table
DNAME
ACCOUNTING
RESEARCH
SALES
OPERATIONS
AFTER UPDATE
ligne
xxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxx
vvvvvvvvvvvvvvvvvvvvvvvvvvvv
vvvvvvvvvvvvvvvvvvvvvvvvvvvv
xxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxx
vvvvvvvvvvvvvvvvvvvvvvvvvvvv
vvvvvvvvvvvvvvvvvvvvvvvvvvvv
xxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxx
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
UPDATE
UPDATE dept
dept
SET
SET deptno
deptno ==
WHERE
WHERE deptno
deptno
Déclencheurs
en cascade
Cours PL/SQL d’après cours ORACLE - OAI / 27
11
== 30;
30;
Déclencheur et Tables Liées (2) :
Déclencheur sur table DEPT
SQL>CREATE
SQL>CREATE OR
OR REPLACE
REPLACE TRIGGER
TRIGGER cascade_updates
cascade_updates
22 AFTER
AFTER UPDATE
UPDATE OF
OF deptno
deptno on
on DEPT
DEPT
33 FOR
FOR EACH
EACH ROW
ROW
44 BEGIN
BEGIN
55
UPDATE
UPDATE emp
emp
66
SET
emp.deptno
SET
emp.deptno == :new.deptno
:new.deptno
77
WHERE
WHERE emp.deptno
emp.deptno == :old.deptno;
:old.deptno;
88 END;
END;
99 //
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 28
Déclencheur et Tables Liées (3) :
Action sur table DEPT
SQL>
SQL> UPDATE
UPDATE dept
dept
22 SET
deptno
SET
deptno == 11
33 WHERE
WHERE deptno
deptno == 30;
30;
**
ERROR
ERROR at
at line
line 1:
1:
ORA-04091:
ORA-04091: table
table DEPT
DEPT is
is mutating,
mutating, trigger/function
trigger/function
may
may not
not see
see it
it
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 29
Consultation de données sur une
table en mise à jour (« Mutating »)
SQL>
SQL>
22
33
UPDATE
UPDATE emp
emp
SET
SET sal
sal == 1500
1500
WHERE
WHERE ename
ename == 'SMITH';
'SMITH';
ERREUR
EMP table
EMPNO
7369
7698
7788
ENAME
SMITH
BLAKE
SCOTT
JOB
CLERK
MANAGER
ANALYST
SAL
1500
2850
3000
BEFORE
UPDATE
ligne
Table en mise à jour
évènement
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
CHECK_SALARY
trigger
Cours PL/SQL d’après cours ORACLE - OAI / 30
Table en mise à jour : exemple - 1
SQL>CREATE
SQL>CREATE OR
OR REPLACE
REPLACE TRIGGER
TRIGGER check_salary
check_salary
22 BEFORE
BEFORE INSERT
INSERT OR
OR UPDATE
UPDATE OF
OF sal,
sal, job
job ON
ON emp
emp
33 FOR
FOR EACH
EACH ROW
ROW
44 WHEN
WHEN (new.job
(new.job <>
<> 'PRESIDENT')
'PRESIDENT')
55 DECLARE
DECLARE
66
v_minsalary
v_minsalary emp.sal%TYPE;
emp.sal%TYPE;
77
v_maxsalary
v_maxsalary emp.sal%TYPE;
emp.sal%TYPE;
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 31
Table en mise à jour : exemple - suite
88
99
10
10
11
11
12
12
13
13
14
14
15
15
16
16
17
17
18
18
19
19
BEGIN
BEGIN
SELECT
SELECT MIN(sal),
MIN(sal), MAX(sal)
MAX(sal)
INTO
INTO v_minsalary,
v_minsalary, v_maxsalary
v_maxsalary
FROM
FROM emp
emp
WHERE
WHERE job
job == :new.job;
:new.job;
IF
IF :new.sal
:new.sal << v_minsalary
v_minsalary OR
OR
:new.sal
:new.sal >> v_maxsalary
v_maxsalary THEN
THEN
RAISE_APPLICATION_ERROR(-20505,
RAISE_APPLICATION_ERROR(-20505,
'salaire
'salaire hors
hors normes');
normes');
END
END IF;
IF;
END;
END;
//
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 32
Table en mise à jour : exemple - suite
SQL>
SQL> UPDATE
UPDATE emp
emp
22 SET
SET sal
sal == 1500
1500
33 WHERE
WHERE ename
ename == 'SMITH';
'SMITH';
**
ERROR
ERROR at
at line
line 22
ORA_4091
ORA_4091 :: Table
Table EMP
EMP is
is mutating,
mutating,
may
may not
not see
see it
it
ORA_06512:
ORA_06512: at
at line
line 44
ORA_04088:
ORA_04088: error
error during
during execution
execution
'check_salary'
'check_salary'
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
trigger/function
trigger/function
of
of trigger
trigger
Cours PL/SQL d’après cours ORACLE - OAI / 33
Utilisation des Déclencheurs
•• S
écurité
Sécurité
•• Audit
Audit
•• Intégrité
Intégrité des
des données
données
•• Intégrité
Intégrité référentielle
référentielle
•• Réplication
Réplication de
de données
données
•• Données
Données dérivées
dérivées
•• Génération
Génération d'événements
d'événements
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 34
Exemple : Intégrité des données
SQL>CREATE
SQL>CREATE OR
OR REPLACE
REPLACE TRIGGER
TRIGGER check_salary
check_salary
22 BEFORE
BEFORE UPDATE
UPDATE OF
OF sal
sal ON
ON emp
emp
33 FOR
FOR EACH
EACH ROW
ROW
44 WHEN
WHEN (new.sal
(new.sal << old.sal)
old.sal) OR
OR
55
(new.sal
(new.sal >> old.sal
old.sal ** 1.1)
1.1)
66 BEGIN
BEGIN
77
RAISE_APPLICATION_ERROR
RAISE_APPLICATION_ERROR (-20508,
(-20508,
88
'Il
'Il ne
ne faut
faut pas
pas diminuer
diminuer le
le salaire
salaire ni
ni
l'augmenter
l'augmenter de
de plus
plus de
de 10%.');
10%.');
10
10 END;
END;
11
11 //
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 35
Exemple : Intégrité référentielle
SQL>CREATE
SQL>CREATE OR
OR REPLACE
REPLACE TRIGGER
TRIGGER cascade_updates
cascade_updates
22 AFTER
AFTER UPDATE
UPDATE OF
OF deptno
deptno ON
ON dept
dept
33 FOR
FOR EACH
EACH ROW
ROW
44 BEGIN
BEGIN
55
UPDATE
UPDATE emp
emp
66
SET
emp.deptno
SET
emp.deptno == :new.deptno
:new.deptno
77
WHERE
WHERE emp.deptno
emp.deptno == :old.deptno;
:old.deptno;
88 END;
END;
99 //
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 36
Exemple : Réplication de données
SQL>CREATE
SQL>CREATE OR
OR REPLACE
REPLACE TRIGGER
TRIGGER emp_replica
emp_replica
22 BEFORE
INSERT
OR
UPDATE
ON
BEFORE INSERT OR UPDATE ON emp
emp
33 FOR
EACH
ROW
FOR EACH ROW
44 BEGIN
BEGIN /*Only
/*Only proceed
proceed if
if user
user init.
init. data
data operation,
operation,
55
NOT
the
casc.
trigger.*/
NOT the casc. trigger.*/
66 IF
INSERTING
IF INSERTING THEN
THEN
77
IF
IF :new.flag
:new.flag IS
IS NULL
NULL THEN
THEN
88
INSERT
INTO
emp@sf
VALUES
INSERT INTO emp@sf VALUES (:new.empno,
(:new.empno,
99
:new.ename,...,'B');
:new.ename,...,'B');
10
:new.flag
10
:new.flag == 'A';
'A';
11
END
IF;
11
END IF;
12
ELSE
12
ELSE /*
/* Updating.
Updating. */
*/
13
IF
13
IF :new.flag
:new.flag == :old.flag
:old.flag THEN
THEN
14
UPDATE
emp@sf
SET
ename
14
UPDATE emp@sf SET ename == :new.ename,
:new.ename, ...,
...,
15
FLAG
=
:new.flag
15
FLAG = :new.flag
16
WHERE
empno
=
:new.empno;
16
WHERE empno = :new.empno;
17
END
17
END IF;
IF;
18
IF
:old.flag
18
IF :old.flag == 'A'
'A' THEN
THEN :new.flag
:new.flag :=
:= 'B';
'B';
19
ELSE
19
ELSE :new.flag
:new.flag :=
:= 'A';
'A';
20
END
20
END IF;
IF;
21
END
IF;
21 END IF;
22
22 END;
END;
23
/
23 /
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 37
Exemple : données dérivées
SQL>CREATE
SQL>CREATE OR
OR REPLACE
REPLACE PROCEDURE
PROCEDURE increment_salary
increment_salary
22 (v_id
IN
dept.deptno%TYPE,
(v_id
IN dept.deptno%TYPE,
33 v_salary
v_salary IN
IN dept.total_salary%TYPE)
dept.total_salary%TYPE)
44 IS
IS
55 BEGIN
BEGIN
66
UPDATE
UPDATE dept
dept
77
SET
total_sal
SET
total_sal == NVL
NVL (total_sal,0)+
(total_sal,0)+ v_salary
v_salary
88
WHERE
WHERE deptno
deptno == v_id;
v_id;
99 END
END increment_salary;
increment_salary;
10
10 //
SQL>CREATE
SQL>CREATE OR
OR REPLACE
REPLACE TRIGGER
TRIGGER compute_salary
compute_salary
22 AFTER
INSERT
OR
UPDATE
OF
sal
AFTER INSERT OR UPDATE OF sal OR
OR DELETE
DELETE ON
ON emp
emp
33 FOR
EACH
ROW
FOR EACH ROW
44 BEGIN
BEGIN
55 IF
IF DELETING
DELETING THEN
THEN increment_salary(:old.deptno,
increment_salary(:old.deptno, -1
-1 ** :old.sal);
:old.sal);
66 ELSIF
UPDATING
THEN
increment_salary(:new.deptno,
ELSIF UPDATING THEN increment_salary(:new.deptno,
77
:new.sal-:old.sal);
:new.sal-:old.sal);
88 ELSE
/*inserting*/
increment_salary(:new.deptno,
ELSE /*inserting*/ increment_salary(:new.deptno, :new.sal);
:new.sal);
99 END
IF;
END IF;
10
10 END;
END;
11
/
11 /
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 38
Exemple : Génération d'événements
SQL>CREATE
SQL>CREATE OR
OR REPLACE
REPLACE TRIGGER
TRIGGER notify_reorder_rep
notify_reorder_rep
22 AFTER
UPDATE
OF
amount_in_stock,
AFTER UPDATE OF amount_in_stock, reorder_point
reorder_point ON
ON inventory
inventory
33 FOR
EACH
ROW
FOR EACH ROW
44 WHEN
WHEN new.amount_in_stock
new.amount_in_stock <=
<= new.reorder_point
new.reorder_point
55 DECLARE
DECLARE
66
v_descrip
product.descrip%TYPE;
v_descrip
product.descrip%TYPE;
77
v_msg_text
VARCHAR2(2000);
v_msg_text
VARCHAR2(2000);
88 BEGIN
BEGIN
99 SELECT
SELECT descrip
descrip INTO
INTO v_descrip
v_descrip
10
FROM
PRODUCT
WHERE
prodid
10 FROM
PRODUCT WHERE prodid == :new.product_id;
:new.product_id;
11
v_msg_text
:=
'It
has
come
to
11 v_msg_text := 'It has come to my
my personal
personal attention
attention that,
that,
12
due
to
recent
'
12
due to recent '
13
CHR(10)
13
CHR(10) ||
|| 'transactions,
'transactions, our
our inventory
inventory for
for product
product ## '||
'||
14
TO_CHAR(:new.product_id)||'--'
14
TO_CHAR(:new.product_id)||'--'
15
||:new.product_name
15
||:new.product_name ||'-||'-- has
has fallen'
fallen' ||
|| CHR(10)
CHR(10) ||
|| CHR(10)
CHR(10) ||
||
16
'Yours,'
||CHR(10)
||user
||
'.';
16
'Yours,' ||CHR(10) ||user || '.';
17
dbms_mail.send
17
dbms_mail.send ('Inventory',
('Inventory', user,null,null,'Low
user,null,null,'Low
18
Inventory',null,v_msg_text);
18
Inventory',null,v_msg_text);
19
END;
19 END;
20
20 //
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 39
Résumé
Procédure
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
vvvvvvvvvvvvvvvvvv
vvvvvvvvvvvvvvvvvv
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
vvvvvvvvvvvvvvvvvv
vvvvvvvvvvvvvvvvvv
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
vvvvvvvvvvvvvvvvvv
vvvvvvvvvvvvvvvvvv
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
vvvvvvvvvvvvvvvvvv
vvvvvvvvvvvvvvvvvv
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
vvvvvvvvvvvvvvvvvv
vvvvvvvvvvvvvvvvvv
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
vvvvvvvvvvvvvvvvvv
vvvvvvvvvvvvvvvvvv
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
Package
Procédure A
déclaration
Procédure B
définition
Procédure A
définition
variable
locale
C.
C. Bonnet
Bonnet // R.
R. Chapuis
Chapuis
Cours PL/SQL d’après cours ORACLE - OAI / 40
Déclencheur