TRIGGER Programmation avancée H.LUU SES Université de Genève H.Luu - Base de données - Eté 2002 Erreur «Mutating Table» Définition : Une table est en état «mutating» si elle est en train d être modifiée par une instruction UPDATE, INSERT, DELETE, ou elle a besoin d être mise à jour à cause des effets de l action DELETE CASCADE. L erreur «mutating table» sera commise si on essaye de lire ou de modifier une table en état «mutating». Cette erreur n a lieu qu avec un trigger au niveau de tuple. H.Luu - Base de données - Eté 2002 2 1
Erreur «Mutating Table» CREATE OR REPLACE TRIGGER maj_trajet BEFORE UPDATE OF villedep, villearr, nbkm ON trajet FOR EACH ROW DECLARE km trajet.nbkm%type; BEGIN SELECT nbkm INTO km FROM trajet WHERE villedep=:new.villedep AND villearr=:new.villearr; IF km <> :new.nbkm THEN RAISE_APPLICATION_ERROR(-20010, Erreur'); END IF; END; H.Luu - Base de données - Eté 2002 3 Solutions «Mutating Table» Solutions d éviter l erreur «mutating table» 1. Transformer un trigger au niveau de tuple à celui au niveau d instruction, ou 2. Utiliser une variable de table PL/SQL, ou 3. Ne pas utiliser des triggers pour implémenter cette RI, mais vérifier la dans les méthodes dont l action peut transgresser la RI. H.Luu - Base de données - Eté 2002 4 2
Corrigé «Mutating table» Utiliser trigger au niveau d instruction => ne pouvoir consulter les valeurs des lignes affectées. Chercher deux tuples (deux trajets) dont les villes de départ et d arrivé sont les mêmes mais les distances en KM sont différentes. 101 GENEVE ZURICH 180 102 GENEVE LAUSANNE 50 209 BERN GENEVE 120 101 GENEVE ZURICH 180 102 GENEVE LAUSANNE 50,,, 202 GENEVE LAUSANNE 60 H.Luu - Base de données - Eté 2002 5 Mutating Table Solution (1) CREATE OR REPLACE TRIGGER maj_sur_trajet AFTER UPDATE OF villedep, villearr, nbkm ON trajet DECLARE CURSOR cur_trajet_1 IS SELECT villedep,villearr,nbkm FROM trajet GROUP BY villedep, villearr, nbkm; CURSOR cur_trajet_2 IS SELECT villedep,villearr,nbkm FROM trajet GROUP BY villedep, villearr, nbkm; vd1 trajet.villedep%type; va1 trajet.villearr%type; nbkm1 trajet.nbkm%type; vd2 trajet.villedep%type; va2 trajet.villearr%type; nbkm2 trajet.nbkm%type; var_exit NUMBER(1) :=0; H.Luu - Base de données - Eté 2002 6 3
Mutating Table Solution (1) BEGIN OPEN cur_trajet_1; LOOP FETCH cur_trajet_1 INTO vd1, va1, nbkm1; OPEN cur_trajet_2; LOOP FETCH cur_trajet_2 INTO vd2, va2, nbkm2; IF vd1=vd2 and va1=va2 and nbkm1<>nbkm2 THEN var_exit:=1; END IF; EXIT WHEN (cur_trajet_2%notfound OR var_exit=1); CLOSE cur_trajet_2; EXIT WHEN (cur_trajet_1%notfound OR var_exit=1); CLOSE cur_trajet_1; IF var_exit=1 THEN RAISE_APPLICATION_ERROR(-20101,'Invalid update'); END IF; END; H.Luu - Base de données - Eté 2002 7 Mutating Table Solution (2) CREATE OR REPLACE TRIGGER maj_sur_trajet AFTER UPDATE OF villedep, villearr, nbkm ON trajet DECLARE TYPE rec_traj IS RECORD (villedep trajet.villedep%type, villearr trajet.villearr%type, nbkm trajet.nbkm%type); TYPE tab_trajet IS TABLE OF rec_traj INDEX BY BINARY_INTEGER; var_tab tab_trajet; rec_1 rec_traj; rec_2 rec_traj; cnt NUMBER(3); n NUMBER(3); m NUMBER(3); CURSOR cur_trajet IS SELECT villedep,villearr,nbkm FROM trajet GROUP BY villedep, villearr, nbkm; H.Luu - Base de données - Eté 2002 8 4
Mutating Table Solution (2) BEGIN /*transférer les données de la table à la collection*/ FOR rec_1 IN cur_trajet LOOP var_tab (cnt) :=rec_1; /*Vérifier la validation de la modification*/ cnt := cur_trajet%rowcount - 1; FOR n IN 0..cnt LOOP rec_1:=var_tab(n); FOR m IN n..cnt LOOP rec_ 2:=var_tab(m); IF (rec_1.villedep=rec_ 2.villedep AND rec_1.villearr=rec_2.villearr AND rec_1.nbkm<>rec_2.nbkm) THEN RAISE_APPLICATION_ERROR(-20001, MAJ non-valide'); END IF; END; H.Luu - Base de données - Eté 2002 9 Erreurs de compilation Erreurs en exécutant des instructions SQL «titre CHAR(30) CONSTRAINT fk_titre_fonds REFERENCES catalogue(titre)» : reprendre l instruction SQL fausse «Erreur à ligne 3» : la ligne où l erreur a lieu. «ORA-02253 : missing right parenthesis» : le code et message d erreur. H.Luu - Base de données - Eté 2002 10 5
Erreurs de compilation La compilation des blocs PL/SQL ou des procédures stockées dans Oracle (par ex. trigger, procédure, ) se termine par un message Si la compilation réussit : <objet> créé(e). H.Luu - Base de données - Eté 2002 11 Erreurs de compilation Si non, Attention : <objet> créé(e) avec erreurs de compilation H.Luu - Base de données - Eté 2002 12 6
Visualiser les erreurs de compilation. Commande SQL*Plus : SHOW ERRORS Line / Col : Ligne / Colonne où l erreur a lieu Ligne : à compte de BEGIN s il n y a pas de «DECLARE», S il y a de «DECLARE» à compter de «DECLARE» Colonne : à compter de la 1ère colonne Error : Code et Message d erreur H.Luu - Base de données - Eté 2002 13 Interpréter des messages d erreur Erreur numérotée commençante par «ORA» : message d erreur du serveur http://cui.unige.ch/doc/oracle8/doc/errmsg80 3/A54625_01/newch2a.htm#1920 Ex. ORA-00907: missing right parenthesis Cause: A left parenthesis has been entered without a closing right parenthesis, or extra information was contained in the parentheses. All parentheses must be entered in pairs. Action: Correct the syntax and retry the statement. H.Luu - Base de données - Eté 2002 14 7
Interpréter des messages d erreur Erreur numérotée commençante par «PLS» : message d erreur PL/SQL http://cui.unige.ch/doc/oracle8/doc/errmsg80 3/A54625_01/newch3.htm#2676 Ex. PLS-00201: identifier name must be declared Cause: An attempt was made to reference either Action: Check the spelling and declaration of the referenced name H.Luu - Base de données - Eté 2002 15 Interpréter des messages d erreur Erreur non-numérotée, référencer la syntaxe pour : Commande SQL*Plus : http://cui.unige.ch/doc/oracle8/doc/server803/a53717 _01/ch7.htm#top Instruction SQL : Oracle8 Server SQL Language Reference Manuel. http://cui.unige.ch/doc/oracle8/doc/server803/a54647 _01/ch4a.htm#3826 Bloc PL/SQL : PL/SQL User s Guide and Reference http://cui.unige.ch/doc/oracle8/doc/server803/a54654 _01/toc.htm H.Luu - Base de données - Eté 2002 16 8