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