143
1 ENIS GI2 ENIS GI2 Faiza Jedidi Faiza Jedidi SGBD : Langage PL_SQL

Cours Plsql

Embed Size (px)

Citation preview

Page 1: Cours Plsql

1

ENIS GI2ENIS GI2

Faiza JedidiFaiza Jedidi

SGBD : Langage PL_SQL

Page 2: Cours Plsql

2

PlanPlan

Chapitre 1 : Introduction à PL/SQL et Structures de contrôle

Chapitre 2 : Interaction avec Oracle et curseurs explicites

Chapitre 3 : Gestion des exceptions

Chapitre 4 : Les sous programmes, les sous programmes stockés et les packages

Chapitre 5 : Declancheurs de BD

Page 3: Cours Plsql

3

PlanPlan

Chapitre 1 : Introduction à PL/SQL et Structures de contrôle

• Introduction• L’environnement PL/SQL• Structure d’un bloc PL/SQL• Types PL/SQL et déclarations

Page 4: Cours Plsql

4

IntroductionIntroduction

• PL/SQL?Extension procédurale à SQL• Avantages de PL/SQL

– Développement de programmes modulaires• Déclaration des identifiants : Variables, Constates,..• Structures de contrôle• Fonctions intégrés• Blocs nommés : sous programmes• Procédures et fonctions stockées• Blocs imbriqués• Package

– Déclencheurs de BD– Portabilité– Intégration– Accroissement des performances

Page 5: Cours Plsql

5

L’environnement PL/SQLL’environnement PL/SQL

• PL/SQL est une technologie employée par Oracle server et par certains outils oracles. Les blocs PL/SQL sont analysés et exécutés par le moteur PL/SQL qui peut se trouver soit dans l’outil, soit dans le serveur Oracle. Le moteur utilisé dépend d’où le bloc a été appelé.

• Le moteur PL/SQL (PL/SQL engine)Lorsque le moteur PL/SQL reçoit un bloc pour exécution, il effectue

les opérations suivantes :– Séparation des ordres SQL et PL/SQL– Passage des commandes SQL au processeur SQL (SQL Statement

Executor)– Passage des instructions procédurales au processeur d’instructions

procédurales (Procedural Statement Executor)

• Moteur PL/SQL dans les outilsCertains outils disposent de leur propre moteur PL/SQL (Oracle

Forms, Oracle Report,…)

Page 6: Cours Plsql

6

Structure d’un bloc PL/SQLStructure d’un bloc PL/SQL

• PL/SQL distingue deux types de blocs : anonymes ou nommés– Bloc anonyme correspond à une séquence d’instructions qui s’exécute

à l’endroit où elle existe– Bloc nommé est un sous programme : fonctions ou procédure

éventuellement paramétrée et pouvant être appelée autant de fois que nécessaire

[ DECLARE--déclaration ]

BEGIN--statements

[EXCEPTION--handlers]END;

Optionnelle

Corps du bloc : Obligatoire

Optionnelle

Page 7: Cours Plsql

7

• ExempleDECLARE – ceci est un bloc anonyme

V_Sal NUMBER (9, 3); --déclarationV_Mess VARCHAR2 (50)

BEGINSELECT Sal INTO V_SalFROM Chercheur WHERE Chno =1234;

EXCEPTIONWHEN NO_DATA_FOUND THEN--gestion de l’exception NO_DATA_FOUNDV_Mess := ‘Chercheur non trouvé’;--suiteEND;

Structure d’un bloc PL/SQLStructure d’un bloc PL/SQL

Page 8: Cours Plsql

8

• Section de déclarationCette section optionnelle introduite par le mot clé DCLARE est

l’unique endroit de déclaration des constantes, variables simples ou composites, curseurs et exceptions utilisateurs.

• Section exécutableCette section obligatoire introduite par le mot clé BEGIN et se

terminant par END contient les instructions du programme et la section de gestion des erreurs si présente. Ces instructions peuvent être :– Instructions d’affectation– Instructions de contrôle de flux– Instructions SQL– Instructions de gestion des curseurs– Instructions de gestion des erreurs

• Section de gestion des exceptionsCette section optionnelle introduite par le mot EXCEPTION est

réservée pour le traitement des erreurs qui pourraient se produire durant l’exécution d’un programme

Structure d’un bloc PL/SQLStructure d’un bloc PL/SQL

Page 9: Cours Plsql

9

Types PL/SQL et déclarationsTypes PL/SQL et déclarations

• Types PL/SQLPL/SQL supporte une variété de type de données utiles pour

déclarer des variables et des constantes – compatibles avec les types Oracle (colonnes de tables)+type BOOLEAN

Type Scalaire Types composés

NUMBER[(précision, scale)] RECORD

VARCHAR2 TABLE

CHAR

DATE

BOOLEAN

Page 10: Cours Plsql

10

Types PL/SQL et déclarationsTypes PL/SQL et déclarations

• Déclarations de variablesIdentificateur Type [(précision, scale)] [NOT NULL] [:=expression];Où Identificateur : règles Oracles habituellesNOT NULL : initialisation obligatoireExemples

DECLARE

….V_sal NUMBER (7,3);V_message VARCHAR2(80):= ‘Texte initial’; Married BOOLEAN:=FALSE;Next_Week DATE :=DATE+7;

• Suivre les conventions suivantes :

Identifiant Préfix Exemple

Variables V_ V_sal

Exception E_ E_RupStock

Variables Hôtes H_ H_Ename

Curseurs C_ C_EMPDEPT10

Paramètre P_ P_EMPNO

Page 11: Cours Plsql

11

• L’attribut %TypeDéclaration de variable en se référant au type d’une variable ou d’une colonne

Identificateur nomTable.colonne%Type;AvantageGarantit la compatibilité de type surtout si la variable déclaré sera cité dans

INTO pour initialisation à partir d’une colonne

ExempleDECLARE…V_deptno1 dept.deptno%TYPE;V_loc dept.loc%TYPE;V_deptno2 deptno%TYPE;BEGIN

SELECT deptno, locINTO v_deptno, v_locFROM …WHERE …

QuestionEst-ce qu’une variable déclaré avec %TYPE en se référant à une colonne NOT

NULL hérite cette contrainte?

Types PL/SQL et déclarationsTypes PL/SQL et déclarations

Page 12: Cours Plsql

12

• Déclaration de constantesIdentificateur CONSTANT Type [(precision,scale)]:=expression;

ExemplePie CONSTANT NUMBER(9.5):=3.14159;

Affectations et expressionsIdentificateur := expression;

ExempleV_compteur :=V_compteur+1;V_message := TO_CHAR(v_compteur);V_ename :=‘KING’;

Les variables logiques reçoivent directement TRUE, FALSE ou bien le résultat d’une expression logique :

Bien_Payé := v_sal>1500;Trouve := TRUE;NotTrouve :=NOT Trouve;

Types PL/SQL et déclarationsTypes PL/SQL et déclarations

Page 13: Cours Plsql

13

• Fonction SQL valides en PL/SQL La plupart des fonctions SQL sont utilisables dans les expressions PL/SQL :

F° numériques mono-ligne :F° caractères mono-ligne :F° Date :F° d’usage divers :

ROUND,…LENGTH, LOWER, UPPER,..SYSDATE,NEXTDAY,LASTDAYDECODE, NVL,

Fonctions SQL NON valides dans les instructions procédurales :GREATEST, LEASTFonctions agrégat (min, max, avg, count, etc.)

Types PL/SQL et déclarationsTypes PL/SQL et déclarations

Page 14: Cours Plsql

14

DECLAREA CHAR ;B NUMBER ;

BEGIN……DECLARE

A INTEGER ;C NUMBER ;

BEGIN …EXCEPTION

…END ;

…EXCEPTION

WHEN …… THEN ….WHEN …… THEN ….

END;

• Blocs Imbriqués et Portée d’une variableParmi les avantages de l’imbrication, on peut citer :

– Une meilleure lisibilité des programmes décomposés en sous-blocs– Un meilleur usage des techniques de gestion et de propagation des

exceptions

Types PL/SQL et déclarationsTypes PL/SQL et déclarations

Page 15: Cours Plsql

15

<<bloc1>>DECLARE

Birthdate DATE ;BEGIN

……DECLARE

Birthdate DATE;BEGIN …

IF Birthdate = bloc1.Birthdate THEN ……END IF;

END ;END bloc1;

• Blocs Imbriqués et Portée d’une variable

Types PL/SQL et déclarationsTypes PL/SQL et déclarations

Page 16: Cours Plsql

16

PlanPlan

Chapitre 2 : Interaction avec Oracle et curseurs explicites

• Introduction• Notion de curseur• Curseurs implicites• Curseurs explicites• Conclusion

Page 17: Cours Plsql

17

IntroductionIntroduction

• Interaction avec Oracle : accéder et manipuler le contenu de la base de données.

• Cette interaction se fait par les commandes SQL utilisées de deux façons : – Autonome : à partir de l’environnement SQL*Plus– Bloc PL/SQL : environnement de développement comme Oracle

Forms, Report, etc.

• Les commandes SQL (SELECT ou du LMD) utilisées dans un bloc PL/SQL sont dites des curseurs.

Page 18: Cours Plsql

18

IntroductionIntroduction

DECLARE

BEGIN SELECT INSERT, UPDATE, DELETE Instructions Procédurales

EXCEPTIONEND ;

Page 19: Cours Plsql

19

Notion de CurseurNotion de Curseur

• A l’exécution d’une commande SQL, Oracle Server ouvre une zone de mémoire dans laquelle la commande est analysée (parsed) et exécutée.

• Cette zone est appelée curseur.

Current Row

Zone Mémoire dans laquelle l’ordre SELECT est compilé etexécuté

On distingue deux types de curseurs :• Les curseurs explicites • Les curseurs implicites 

Page 20: Cours Plsql

20

Notion de curseurNotion de curseur

• Les curseurs explicites– C’est une commande SELECT pouvant ramener plusieurs

lignes et qui est totalement à la charge du développeur. – Un curseur explicite doit être explicitement :

• Déclaré dans la section DECLARE• Géré par le développeur dans la section exécutable. La gestion

d’un curseur consiste à exécuter les opérations : ouverture du curseur, lecture et traitement des lignes, fermeture.

Page 21: Cours Plsql

21

• Les curseurs implicites– Un curseur implicite est toute commande SQL (Select, Insert,

Update, Delete) située dans la partie exécutable d’un bloc :• NON déclaré explicitement • Nommé ‘SQL’ implicitement par Oracle : tester l’état du curseur• Gestion automatique par PL/SQL : ouverture, traitement,

fermeture.

– Lorsque le curseur implicite est un ordre SELECT, alors il doit ramener une seule ligne, sinon erreur.

Notion de curseurNotion de curseur

Page 22: Cours Plsql

22

Les curseurs implicitesLes curseurs implicites

• Le tableau suivant indique, par opération de manipulation, les commandes SQL susceptibles de jouer le rôle de curseur implicite et/ou explicite :

Opération Curseur implicite Curseur explicite

MAJ Insert, Update, Delete

Aucune*

Interrogation Select …Into Select**

* Il n’existe pas de curseur explicite de mise à jour** Un curseur explicite ne peut être qu’un select

Page 23: Cours Plsql

23

Les curseurs implicitesLes curseurs implicites

• ExempleDECLAREV_deptno NUMBER(2);V_Loc VARCHAR2(15);.....BEGINSELECT deptno, locINTO v_deptno, v_loc ObligatoireFROM dept

WHERE upper(dname) = ‘SALES’;…END;

Si le SELECT ne ramène pas exactement une ligne, PL/SQL réagit contre ces erreurs en levant (raise) des exceptions qu’on peut piéger (trap) et gérer dans la section EXCEPTION.

Page 24: Cours Plsql

24

• Exceptions du SELECTExceptions du SELECT

Condition Nom Exception

Le SELECT identifie plus d’une ligneErreur Oracle Server ORA-01422

TOO_MANY_ROWS

Le SELECT n’identifie aucune ligneErreur Oracle Server ORA-01403

NO_DATA_FOUND

Les curseurs implicitesLes curseurs implicites

Page 25: Cours Plsql

25

Les curseurs implicitesLes curseurs implicites

• Attributs du curseur implicitePL/SQL fournit des attributs permettant d’évaluer le résultat d’un

curseur implicite :

Attribut Description

SQL%ROWCOUNT Entier : Nombre de lignes affectées par le dernier ordre SQL

SQL%FOUND Booléen : TRUE si le dernier ordre SQL affecte au moins une ligne

SQL%NOTFOUND Booléen : TRUE si le dernier ordre SQL n’affecte aucune ligne

SQL%ISOPEN Toujours FALSE pour les curseurs implicites.

Ces attributs sont utilisables comme des fonctions dans les ordres PL/SQL MAIS PAS dans les commandes SQL.

Page 26: Cours Plsql

26

• ExempleDECLAREV_Rows_Updated NUMBER; BEGIN UPDATE EMP SET sal = sal*1.1 WHERE deptno = 10;

V_Rows_Updated := SQL%ROWCOUNT;

-- SQL%ISOPEN est FALSEINSERT INTO History_TabValues (‘Dept 10’, V_Rows_Updated, SYSDATE);

END ;

Les curseurs implicitesLes curseurs implicites

Page 27: Cours Plsql

27

• Les variables PL/SQL qui risquent d’être utilisées dans des ordres SQL doivent être différentes des noms de colonnes des tables manipulées :

DECLAREempno NUMBER(4) := 7788; BEGINUPDATE EMPSET sal = 9000WHERE empno = empno;  !!Toutes les lignes

seront MAJ

… (V_empno) END ;

Les curseurs implicitesLes curseurs implicites

Page 28: Cours Plsql

28

Les curseurs explicitesLes curseurs explicites• Motivation

– Besoin de consulter n-uplets issus d’une ou de plusieurs tables de la base de données

– Effectuer des traitements en examinant chaque ligne individuellement

• Curseur explicite – Est une commande Select déclaré et nommé– Généralisation du curseur implicite d’interrogation– Possédant les quatre attributs suivants : %ISOPEN%ISOPEN, %FOUND%FOUND,

%NOTFOUND%NOTFOUND et %ROWCOUNT%ROWCOUNT.

• Exigences du curseur explicite

– Déclaration– Ouverture– Accès aux lignes du curseur– Fermeture

Section DECLARE

Section EXECUTABLE

Page 29: Cours Plsql

29

Les curseurs explicitesLes curseurs explicites

• Déclaration d’un curseur : Syntaxe

CURSOR nom_curseurCURSOR nom_curseur [(paramètre1, paramètre2,…)] IS Commande_SELECTIS Commande_SELECT [FOR UPDATE [OF colonne1, colonne2,…] [NOWAIT]];;

nom_curseur : est le nom du curseur

Commande_SELECT : est une requête pouvant utiliser les clauses habituelles (group by, having, order by

Paramètre : est un paramètre formel décrit comme suit :

Nom_paramètre [IN] Type [{:=|DEFAULT} valeur]

FOR UPDATE [OF colonne1, colonne2,…] : place un verrou exclusif portant sur des n-uplets de la table du SELECT

[OF colonne1, colonne2,…] : les colonnes à mettre à jour par le curseur sont verrouillées

NOWAIT : pas d’attente pour accéder aux n-uplets

Page 30: Cours Plsql

30

Les curseurs explicitesLes curseurs explicites• Déclaration d’un curseur : ExemplesDECLARE

……

CURSOR C1_Cher IS – curseur non paramétré

SELECT Cnom, Labno

FROM chercheur

WHERE Sal> 1200;

**************************************************************

CURSOR C2_Cher (P_Labno IN NUMBER) IS

-- IN est optionnel

SELECT Grade, Cnom

FROM chercheur

WHERE Labno = P_Labno;

**************************************************************

CURSOR C3_CHER (P_Min NUMBER DEFAULT 0, P_Max NUMBER DEFAULT 99) IS

SELECT ….

FROM ….

WHERE BETWEEN P_Min AND P_Max;

Page 31: Cours Plsql

31

Les curseurs explicitesLes curseurs explicites• Ouverture d’un curseur : SyntaxeOPEN nom_curseur [(paramètre_effectif,…)];

• ExemplesOPEN C1_Cher;OPEN C1_Cher;

OPEN C2_Cher (10);|V_Labno :=10;OPEN C2_Cher (10);|V_Labno :=10;

OPEN C2_Cher (V_Labno);OPEN C2_Cher (V_Labno);

OPEN C3_Cher;OPEN C3_Cher;

OPEN C2_Cher (10);|OPEN C2_Cher (10);|

SELECT Grade, CnomFROM chercheurWHERE Labno = 10;

Manager CLARKPresident kINGClerk Miller

Current ROW

Active Set of Rows

ZONE

Mémoire où l’ordre SELECT est compilé et exécuté

Page 32: Cours Plsql

32

Les curseurs explicitesLes curseurs explicites

• Accès aux lignes d’un curseur : SyntaxeFETCHFETCH nom_curseur INTOINTO variable1, variable2,…;

• Fonctionnalités– Ramène le contenu de la ligne courante– Assigne les données dans les variables de INTO– Déplace le pointeur vers la ligne suivante

Page 33: Cours Plsql

33

• Accès aux lignes d’un curseur : ExempleDECLAREDECLARECURSOR C1_Cher IS

SELECT Cnom, LabnoFROM ChercheurWHERE Sal >1400;

V_Cnom Chercheur.Cnom%TYPE;V_Labno Chercheur.Labtno%TYPE;BEGINBEGINOPEN C1_Cher;--Exécution du SELECTLOOPLOOP

FETCH C1_Cher INTO V_Cnom, V_Labno;EXIT WHEN C1_Cher%NOTFOUND;--Test de sortie-- ici %FOUND est TRUE-- traitement de la ligne ramenée par FETCH…

END LOOP;END LOOP;…ENDEND; --fin du bloc

Les curseurs explicitesLes curseurs explicites

Page 34: Cours Plsql

34

Les curseurs explicites Les curseurs explicites • Fermeture d’un curseur Fermeture d’un curseur

– Libération de l’espace mémoire alloué– Réouverture si nécessaire

• SyntaxeSyntaxe

CLOSECLOSE nom_curseur;

• RemarqueRemarquetoute opération sur un curseur fermé (Fetch, %attribut) engendra l’exception prédéfinie INVALID_CURSOR

• Attributs d’un curseur expliciteAttributs d’un curseur explicite– %FOUND

Cet attribut prend la valeur TRUE lorsque une ligne est ramenée, sinon il prend la valeur FALSE

– %NOTFOUNDCet attribut prend la valeur FALSE lorsque une ligne est ramenée, sinon il prend

la valeur TRUE – %ISOPEN

Cet attribut prend la valeur TRUE lorsque le curseur indiqué est ouvert, sinon il prend la valeur FALSE

– %ROWCOUNTCet attribut retourne le nombre de lignes impactées par la dernière instruction SQL

Page 35: Cours Plsql

35

Les curseurs explicitesLes curseurs explicites• Curseur et enregistrement : SyntaxeNom_enregistrement nom_curseur%ROWTYPE;• ExempleDECLAREDECLARECURSOR C1 IS

SELECT Cnom, Sal+NVL(prime,0) salaireFROM chercheurWHERE Labno=10;

Rec1 C1%ROWTYPERec1 C1%ROWTYPE;-- Rec1 de même schéma que C1V_Cnom Chercheur.Cnom%TYPE;…BEGINBEGINOPEN C1;LOOP

FETCH C1 INTO Rec1FETCH C1 INTO Rec1;EXIT WHEN C1%NOTFOUND OR C1%ROWCOUNT >5;V_Cnom:=Rec1.Cnom;V_Salaire := Rec1.salaire;

END LOOP;Close C1;ENDEND;__ fin bloc

Page 36: Cours Plsql

36

Les curseurs explicitesLes curseurs explicites• Clauses WHERE CURRENT OF et FOR UPDATE Les commandes SQL (UPDATE et DELETE) peuvent utiliser la clause

«WHERE CURRENT OF nom_curseur» pour référencer la ligne courante d’un curseur explicite

• ExempleDECLAREDECLARE

CURSOR C1 ISSELECT Cnom, Labno FROM ChercheurWHERE Sal>1400 FOR UPDATE of Labno;

Ligne_C1 C1%ROWTYPE;BEGINBEGINOPEN C1;LOOPLOOP

FETCH C1 INTO Ligne_C1;EXIT WHEN C1%NOTFOUND;IFIF Ligne_C1.Labno=10 Then

UPDATE ChercheurSET Labno =99—supposé existantWHERE CURRENT OF C1WHERE CURRENT OF C1;

END IFEND IF-- suite de traitementEND LOOPEND LOOP;CLOSE C1;Commit;ENDEND; --fin bloc

Page 37: Cours Plsql

37

Les curseurs explicitesLes curseurs explicites• Boucle dédiée curseur

PL/SQL offre une boucle FOR spéciale pour les curseurs explicites. Elle prend en charge toutes les opérations du curseur (OPEN, FETCH, EXIT et CLOSE)

• Syntaxe 1 : cas d’un curseur nomméSyntaxe 1 : cas d’un curseur nomméFOR nom_record IN nom_curseur [(paramètre,…)]

LOOP

--traitement de la ligne courante

END LOOP;

• Syntaxe 2 : cas d’un curseur anonymeSyntaxe 2 : cas d’un curseur anonymeFOR nom_record IN (Commande_SELECT)

LOOP

--traitement de la ligne courante

END LOOP;

Page 38: Cours Plsql

38

• Boucle dédiée curseur : Exemple 1DECLAREDECLARE

CURSOR C1 (P_DATEREC DATE) IS

SELECT Cnom, Grade FROM Chercheur

WHERE DATEREC < P_DATEREC;

BEGINBEGIN

FOR REC IN C1 (’01-JAN-99’) -- curseur ouvert

LOOPLOOP -- ici une ligne est disponible

-- traitement des lignes, une par itération

END LOOP;END LOOP;

/* Ici le curseur est automatiquement fermé

les attributs ne sont pas utilisables

Toute référence à REC est invalide*/

-- suite traitement

END;END;

Les curseurs explicitesLes curseurs explicites

Page 39: Cours Plsql

39

• Boucle dédiée curseur : Exemple 2

DECLAREDECLARE

……

BEGINBEGIN

V_TOT_SAL NUMBER :=0;

FOR REC IN (SELECT Cnom, SalFOR REC IN (SELECT Cnom, Sal

FROM ChercheurFROM Chercheur

WHERE Labno=10)WHERE Labno=10)

LOOPLOOP

-- traitement de la ligne courante

IF Rec.Sal > 1000 THEN …

END LOOP;END LOOP;

……..

END;END;

Les curseurs explicitesLes curseurs explicites

Page 40: Cours Plsql

40

ConclusionConclusion• Notion de curseurNotion de curseur : une zone de mémoire dans laquelle la commande

est analysée (parsed) et exécutée

• Curseurs implicitesCurseurs implicites– Curseur implicite : SELECT …INTO– Autres curseurs implicites : INSRET, UPDATE et DELETE après BEGIN– Attributs des curseurs implicites :SQL%ROWCOUNT, SQL%FOUND, SQL

%NOTFOUND, SQL%ISOPEN

• Curseurs explicitesCurseurs explicites– Déclaration de curseur CURSOR– Ouverture de curseur OPEN– Accès aux lignes d’un curseur FETCH– Fermeture de curseur CLOSE– Attributs d’un curseur explicite :%ROWCOUNT, %FOUND, %NOTFOUND,

%ISOPEN– Curseur et enregistrement : Nom_enregistrement nom_curseur

%ROWTYPE– Clauses WHERE CURRENT OF et FOR UPDATE– Boucle dédiée curseur : gestion automatique de toutes les opérations

d’un curseur (OPEN, FETCH, EXIT et CLOSE)

Page 41: Cours Plsql

41

PlanPlan

Chapitre 3 : Gestion des exceptions

1. Introduction2. Gestion des exceptions3. Propagation des exceptions4. Envoie de message d’erreur avec

RAISE_APPLICATION_ERROR5. Traitement des exceptions dans les autres

environnements

Page 42: Cours Plsql

42

IntroductionIntroduction

• Lors de l’exécution d’un bloc PL/SQL, certaines erreurs peuvent se produire. Les conditions de ces erreurs sont appelés des exceptions

• Oracle distingue deux types d’exception :

– Les exceptions internes

– Les exceptions utilisateur (User-Exceptions)

Page 43: Cours Plsql

43

IntroductionIntroduction

• Les exceptions internes

– Détecter implicitement par le serveur Oracle

– Elles sont libellées et codées (ORA-XXXXX)

– Deux types d’exception internes :

• Nommées (ou Prédéfinies)

• Anonymes (ou Non prédéfinies)

Page 44: Cours Plsql

44

IntroductionIntroduction

• Les exceptions utilisateur

– Détecter explicitement par le développeur

– Elles sont définies dans la section DECLARE

• Une exception non traitée, interne ou utilisateur, provoque l’échec du bloc PL/SQL

• Pour se protéger contre ces situations, il est possible de gérer ces exceptions. La gestion d’une exception consiste à prévoir un traitement approprié qui absorbe ou résout l’erreur. L’endroit de ce traitement est la section EXCEPTION

Page 45: Cours Plsql

45

Gestion des exceptionsGestion des exceptions

• En cas d’une exception rencontrée dans la section exécutable d’un bloc le contrôle passe immédiatement à la section EXCEPTION du même bloc pour chercher si un gestionnaire approprié existe

DECLARE

BEGIN

EXECPTION

END;

Erreur

Recherche d’un gestionnaire approprié

Page 46: Cours Plsql

46

Gestion des exceptionsGestion des exceptions• Comment gérer une exception?

Gérer une exception c’est prévoir un traitement correspondant à l’erreur rencontrée

• Pourquoi gérer une exception?

Transformer un échec en succès

Eviter la propagation de l’exception vers les blocs parents

• Où gérer une exception?

Tout bloc PL/SQL prévoit une section optionnelle de gestion des exceptions

Page 47: Cours Plsql

47

Gestion des exceptionsGestion des exceptions• Syntaxe

-- corps du bloc

EXCEPTION

WHEN Nom_Exception THEN

Instructions; -- gestionnaire d’exception

WHEN

[WHEN OTHERS THEN

…;]

END;-- fin du bloc

Nom_Exception : interne ou utilisateur

Page 48: Cours Plsql

48

Gestion des exceptionsGestion des exceptions• Exemple

DECLAREDECLARE

V_Cnom Chercheur.Cnom%TYPE;

BEGINBEGIN

SELECT Cnom

INTO V_Cnom

FROM Chercheur

WHERE Labno =10;

DBMS_OUTPUT.PUT_LINE (‘Nom Chercheur’||V_Cnom);

ExceptionException

WHEN TOO_MANY_ROWS TOO_MANY_ROWS THEN

DBMS_OUTPUT.PUT_LINE (‘Plusieurs chercheurs Trouvés.’);

--Utiliser un curseur explicite

ENDEND;

Page 49: Cours Plsql

49

Gestion des exceptionsGestion des exceptions

• Exceptions prédéfinies (internes)

– Elles sont prédéfinies par Oracle

– Elles possèdent des noms significatifs

– Elles sont automatiquement provoquées

– Les exceptions les plus courantes sont les suivantes :

• Exception DUP_VAL_ON_INDEX (ORA-00001)

• Exception NO_DATA_FOUND (ORA-01403)

• Exception TOO_MANY_ROWS (ORA-01422)

• Exception VALUE_ERROR (ORA-06502)

• Exception INVALID_NUMBER (ORA-01722)

• Exception ZERO_DIVIDE (ORA-01476)

• Exception INVALID_CURSOR (ORA-01722)

Page 50: Cours Plsql

50

Gestion des exceptionsGestion des exceptions

• Exception DUP_VAL_ON_INDEX (ORA-00001)

– Condition de provocation : lorsqu’une commande SQL tente d’insérer une valeur dupliquée dans une colonne définie avec un index unique (UNIQUE INDEX ou PRIMARY KEY)

– Exemple : cas d’insertion avec duplication de clé primaire

BEGIN

INSERT INTO Etudiant (NumETUD, NomETUD, FilETUD)

VALUES (10, ‘Dupont’, ‘Informatique’);

EXCEPTION

WHEN DUP_VAL_ON_INDEXDUP_VAL_ON_INDEX THEN

DBMS_OUTPUT.PUT_LINE (‘Insertion rejetée :NumETUD existe déjà.’);

END;

Page 51: Cours Plsql

51

Gestion des exceptionsGestion des exceptions

• Exception NO_DATA_FOUND (ORA-01403)– Condition de provocation : lorsqu’un curseur implicite

d’interrogation ne retourne aucune ligne– Exemple : cas de recherche d’un étudiant inexistant

DECLARE

ETUDIANT_REC ETUDIANT%ROWTYPE;

V_NumETUD ETUDIANT.NumETUD%TYPE :=10;

BEGIN

SELECT * INTO ETUDIANT_REC

FROM ETUDIANT WHERE NumETUD= V_NumETUD;

EXECPTION

WHEN NO_DATA_FOUND THEN

DBMS_OUTPUT.PUT_LINE (‘Etudiant 10 Inexistant’);

END;

– Remarque : L’absence d’un gestionnaire pour l’exception NO_DATA_FOUND entraîne une sortie du bloc avec échec

Page 52: Cours Plsql

52

Gestion des exceptionsGestion des exceptions

• Exception TOO_MANY_ROWS (ORA-01422)– Condition de provocation : lorsqu’un curseur implicite

d’interrogation identifie plus qu’un seul n-uplet à retourner– Exemple : plusieurs étudiants ayant la même filière

DECLARE

V_NomETUD ETUDIANT.NomETUD%TYPE;

BEGIN

SELECT NomETUD

INTO V_NomETUD

FROM ETUDIANT WHERE FilETUD= ‘Informatique’;

EXECPTION

WHEN TOO_MANY_ROWS THEN

DBMS_OUTPUT.PUT_LINE (‘Plusieurs étudiants trouvés.’);

END;

Page 53: Cours Plsql

53

Gestion des exceptionsGestion des exceptions

• Exception VALUE_ERROR (ORA-06502)

– Condition de provocation : en cas de troncature ou d’erreur de conversion

– Exemple : Affectation générant une troncature

DECLARE

V_message VARCHAR2 (10);

BEGIN

V_message :=‘Chaîne trop longue’;

EXCEPTION

WHEN VALUE_ERRORVALUE_ERROR THEN

DBMS_OUTPUT.PUT_LINE (‘Erreur de troncature’);

END;

Page 54: Cours Plsql

54

Gestion des exceptionsGestion des exceptions

• Exception INVALID_NUMBER (ORA-01722)– Condition de provocation : lorsqu’une commande SQL spécifie

un nombre invalide

– ExempleDECLARE

V_mgr VARCHAR2 (4);

BEGIN

UPDATE EMP

SET MGR = V_mgr

WHERE empno=7902;

EXCEPTION

WHEN INVALID_NUMBER INVALID_NUMBER THEN

DBMS_OUTPUT.PUT_LINE (‘Exception INVALID_NUMBER’);

END;

Page 55: Cours Plsql

55

Gestion des exceptionsGestion des exceptions• Exception ZERO_DIVIDE (ORA-01476)

– Condition de provocation : tentative de division par ZERO

– ExempleDECLARE

V_nombre1 int :=10;

V_nombre2 int :=5;

V_resultat number (5,3);

BEGIN

V_resultat := 100/(V_nombre1 -2* V_nombre2);

EXCEPTION

WHEN ZERO_DIVIDEZERO_DIVIDE THEN

DBMS_OUTPUT.PUT_LINE (‘Exception ZERO_DIVIDEException ZERO_DIVIDE’);

END;

Page 56: Cours Plsql

56

Gestion des exceptionsGestion des exceptions

• Exception INVALID_CURSOR (ORA-01722)

– Condition de provocation : au moment ou un curseur fermé est référencé dans une opération de lecture (FETCH), de fermeture (CLOSE) ou via des attributs (%FOUND, %NOTFOUND, %ROWCOUNT)

Page 57: Cours Plsql

57

Gestion des exceptionsGestion des exceptions

• Exceptions génériques OTHERS— Condition de provocation : toute exception non gérée— WHEN OTHERS doit être la dernière

• Les fonctions SQLCODE et SQLERRMQuand une exception se produit, on peut récupérer son code et son

message d’erreur. Ceci est particulièrement intéressant pour les exceptions manipulées avec OTHERS

SQLCODE SQLCODE : Renvoie un entier représentant le n° de l’erreur (99999) qui a provoquée l’exception et Zéro sinon (pas d’erreur)

SQLERRM :SQLERRM : Renvoie un texte composé du numéro de l’erreur et d’un message complet associé à l’exception rencontrée, de la forme (ORA-XXXX: texte explicatif)

Page 58: Cours Plsql

58

Gestion des exceptionsGestion des exceptions

• Exceptions de l’utilisateur

Toute exception utilisateur doit être déclarée et explicitement provoquée pour la capturer selon les étapes suivantes :

– Déclaration : syntaxe

Nom_exception EXCEPTION;

– Déclenchement : syntaxe

RAISE nom_exception;

– Capture : syntaxe

WHEN nom_exception THEN instructions;

Page 59: Cours Plsql

59

Gestion des exceptionsGestion des exceptions!!• Exceptions de l’utilisateur

– Exemple DECLARE

E_Rupt_Stk EXCEPTION;--déclarationE_Rupt_Stk EXCEPTION;--déclaration

V_Qtestk Art.Qtestk%TYPE;

V_Qtestksec Art.Qtestksec%TYPE;

BEGIN

SELECT Qtestk, Qtestksec

INTO V_Qtestk, V_Qtestksec

FROM Stock WHERE Numart=1234;

--suite

IF V_Qtestk <V_Qtestsec THEN

RAISE E_Rupt_Stk; --provocationRAISE E_Rupt_Stk; --provocation

END IF;

--suite

EXCEPTION

WHEN E_Rupt_Stk THEN --gestionnaireWHEN E_Rupt_Stk THEN --gestionnaire

DBMS_OUTPUT.PUT_LINE (‘Stock insuffisant,article 1234’);

END;

Page 60: Cours Plsql

60

Gestion des exceptionsGestion des exceptions• Exceptions internes non prédéfinies

Les exceptions internes non prédéfinies peuvent être piégées par la clause générique WHEN OTHERS.

PL/SQL offre une souplesse additionnelle au développeur en permettant de nommer des erreurs internes ce qui permettra de les distinguer individuellement et de les utiliser comme les exceptions prédéfinies.

Les erreurs internes pour lesquelles le développeur assigne un nom sont dites des exceptions Non Prédéfinies

• Etapes de capture d’une Exception Non Prédéfinie1. Déclarer l’exception

Nom_exception EXCEPTION ;

2. Associer l’exception déclarée à un numéro d’erreur interne

PRAGMA EXCEPTION_INIT (nom_exception, no_err_interne) ;

3. Prévoir un gestionnaire d’exception1. Idem ;

• Remarque : les exceptions internes :– sont provoquées implicitement– peuvent être provoquées explicitement (RAISE nom_except).

Page 61: Cours Plsql

61

• Exemple

DECLARE Privilege_Insuffisant EXCEPTION; PRAGMA EXCEPTION_INIT(Privilege_Insuffisant, -1031); /*Oracle return error number -1031 if, for example, you try to

UPDATE a table for which you have only SELECT privileges */BEGIN ...…EXCEPTION WHEN Privilege_Insuffisant THEN-- Gestionnaire d’exception END;

Gestion des exceptionsGestion des exceptions

Page 62: Cours Plsql

62

Propagation des exceptionsPropagation des exceptions

• Principe

Lorsqu’un sous-bloc traite une exception, il se termine normalement (succès) et le contrôle reprend dans le bloc parent immédiatement après l’instruction END du sous-bloc. Lorsqu’une exception n’est pas gérée dans son bloc, elle se transmet au bloc parent : cette transmission de l’erreur entre blocs est appelée propagation.

Page 63: Cours Plsql

63

Propagation des exceptionsPropagation des exceptions• Exceptions de la section exécutable

BEGIN

……

-- Exception X déclenché ici

EXCEPTION – Aucun gestionnaire pour l’exception X

END;

Exception

-- il y a un gestionnaire pour l’exception x

END;

Propagation

Page 64: Cours Plsql

64

Propagation des exceptionsPropagation des exceptions

• Avantages de la propagation

– Gérer les exceptions spécifiques à certaines instructions au niveau de leur bloc pour assurer la sûreté de fonctionnement de ces blocs

– Ceci permettra également d’éviter une reproduction en cascade de l’erreur

Page 65: Cours Plsql

65

Propagation des exceptionsPropagation des exceptions• Exceptions de la section DECLAREToute exception provoquée par l’initialisation d’une variable lors de sa

déclaration se propage et ne peut être traitée dans son bloc même si un gestionnaire d’exception approprié (ou OTHERS) y est prévu.

DECLARE

V_NO NUMBER (3):=‘ABC’

BEGIN

….

EXCEPTION

WHEN OTHERS THEN

END;

Affectation illégale, provoque l’exception VALUE_ERROR

Ne peut être exécutée pour l’exception VALUE_ERROR

Bloc en échec

Exception VALUE_ERROR reconduite

Page 66: Cours Plsql

66

Propagation des exceptionsPropagation des exceptions

• Exceptions de la section EXCEPTIONUn gestionnaire d’exception peut provoquer une autre exception

implicitement (interne) ou explicitement (RAISE), auxquels cas, l’exception se propage et ne peut être capturée dans le même bloc : le principe est d’activer un seul gestionnaire d’exception à la fois dans un bloc

• ExempleEXCEPTION

WHEN INVALID_NUMBER THENINSERT INTO …--peut causer DUP_VAL_ON_INDEX

WHEN DUP_VAL_ON_INDEX THEN…

END;

Page 67: Cours Plsql

67

Propagation des exceptionsPropagation des exceptions

• Gestion locale et reproduction d’une exceptionParfois, on a besoin de traiter localement une exception provoquée

puis de la transmettre au bloc parent. La commande RAISE permet cette reproduction de l’erreur

EXCEPTION WHEN E_STOCK_INSUFFISANT THEN

-- Gérer localement l’erreur RAISE; --Reproduit l’exception courante . . . .END; -- fin sous blocEXCEPTION WHEN E_STOCK_INSUFFISANT THEN

-- Gérer l’erreur différemment . . . .END ;

Page 68: Cours Plsql

68

Envoie de message d’erreur avec Envoie de message d’erreur avec RAISE_APPLICATION_ERRORRAISE_APPLICATION_ERROR

• RAISE_APPLICATION_ERROR est une procédure du package DBMS_STANDARD, utile pour produire des messages d’erreur applicatifs spécifiques à l’environnement appelant (SQL*Plus, s/p PL/SQL, application client). L’exécution de RAISE_APPLICATION_ERRORRAISE_APPLICATION_ERROR reproduit l’erreur et annule la transaction en cours. Elle est utilisable dans les sections BEGIN et EXCEPTION.

• Syntaxe RAISE_APPLICATION_ERROR (no_erreur, message_erreur);

no-erreur : doit être compris entre -20000 et -20999

message-erreur : texte de 512 caractères maximum

DECLARE

E_mon-Exception EXCEPTION ;

BEGIN

….

Raise E_mon-Exception;

….

EXCEPTION

WHEN E_mon-Exception THEN

RAISE_APPLICATION_ERROR(-20000, ‘message applicatif’);

END ;

Page 69: Cours Plsql

69

Traitement des exceptions dans les autres Traitement des exceptions dans les autres environnementsenvironnements

• Il est possible de propager une exception vers l’environnement appelant au lieu de la traiter dans le bloc PL/SQL courant

• Chaque environnement possède sa propre façon de traiter les erreurs.

Environnement appelant

Possibilité de traitement des Exceptions

SQL* Plus ou Procedure Builder

Le libellé et le numéro des exceptions non traitées sont affichés à l’écran.

Developer/2000 Forms Le libellé et le numéro des exceptions non traitées sont accessibles par un trigger au moyen des fonctions ERROR_CODE et ERROR_TEXT.

Précompilateur C Le numéro des exceptions non traitées est accessibles via la structure SQLCA.

Page 70: Cours Plsql

70

PlanPlan

Chapitre 4 : Les sous programmes, les sous programmes stockés et les packages

1. Les sous programmes2. Les sous programmes stockés3. Les packages

Page 71: Cours Plsql

71

PlanPlan

Section 1 : Les sous programmes

1. Introduction2. Procédures

1. Modes de passage des paramètres2. Correspondance entre paramètres Actuels et

Formels3. Fonctions4. Exceptions dans les sous programmes et impact

sur les paramètres5. Appels Mutuels entre sous programmes

Page 72: Cours Plsql

72

IntroductionIntroduction

• Bien que PL/SQL permet l’imbrication de blocs, cette pratique n’est pas recommandée pour deux raisons majeures :

– Réduit la lisibilité du code et rend plus difficile sa maintenance

– Les blocs emboîtés ne peuvent pas être appelés

• Les sous programmes

– PL/SQL offre la possibilité de travailler avec des sous programmes

– Un sous programme PL/SQL est un bloc nommé défini dans la section DECLARE et pouvant posséder des paramètres

– Il est réutilisable et facilite la maintenance des applications

Page 73: Cours Plsql

73

ProcéduresProcédures• Syntaxe

PROCEDURE nom_procédure [(paramètre [, paramètre…])]{IS |AS}/*déclarations si nécessaires*/BEGIN--instructions exécutables[EXCEPTION--Section optionnelle de --Gestion des exceptions ]END [nom_procédure];

Page 74: Cours Plsql

74

ProcéduresProcédures

• Exemple 1 (procédure sans paramètres)Enregistrer l’utilisateur courant et la date système dans la table Tab_Trace

(User_Uid, User_Name, User_Trace_Date)

DECLAREDECLARE….PROCEDUREPROCEDURE RECORD_Trace As BEGINBEGININSERT INTO Tab_Trace(User_Uid, User_Name, User_Trace_Date)VALUES (UID, USER, SYSDATE);EXCEPTIONEXCEPTIONWHEN OTHERS THENDBMS_OUTPUT.PUT_LINE (SUBSTR (SQLERRM, 1,80);ENDEND RECORD_Trace;-- autres déclarations

BEGIN –début bloc externe

RECORD_Trace;--appel procédure

END;--fin bloc externe

Page 75: Cours Plsql

75

ProcéduresProcédures• Exemple 2 (procédure avec paramètres)Augmenter le salaire d’un employé identifié par EMPNO d’un montant donné

DECLARE….PROCEDUREPROCEDURE AUGMENTE_SAL (P_EMPNO EMP.EMPNO%TYPE, P_Montant

NUMBER) ISBEGINBEGINUPDATE EMPSET SAL =SAL+P_MontantWHERE EMPNO=P_EMPNOAND P_EMPNO NOT NULL;IF SQL%NOTFOUND THENDBMS_OUTPUT.PUT_LINE (‘MAJ Non Effectuée’);ELSEDBMS_OUTPUT.PUT_LINE (‘MAJ Réussie’);END IFEND AUGMENTE_SAL;-- autres déclarations

BEGIN –début bloc externeAUGMENTE_SAL (1234,1000);

END;--fin bloc externe

Page 76: Cours Plsql

76

Modes de passage des paramètresModes de passage des paramètres

• Nom_param [IN|OUT|IN OUT ] Type [{:=|DEFAULT} expr]

Paramètre formel Paramètre d’appelIN (read-only) (1) Le sous PG reçoit une copieOUT (write-only) (2) Le sous PG fournit un résultatIN OUT (read-write) (1)&(2)

IN : Passage par valeurIN OUT : Passage par @ échange dans les deux sensOUT : Passage par @ pour retourner un résultat

Page 77: Cours Plsql

77

Modes de passage des paramètresModes de passage des paramètres• Exemple

PROCEDUREPROCEDURE ModeParam (P_In IN NUMBER, P_Out OUT NUMBER, P_InOut NUMBER ) IS

V_Local NUMBER;BEGINBEGINP_In :=20; -- Affectation illégaleP_Out est null iciP_Out:=10; --légaleV_local :=P_Out; --illégale (Write only)P_InOut reçoit la valeur du param d’appelP_InOut :=P_InOut*3;ENDEND ModeParam;

Page 78: Cours Plsql

78

Modes de passage des paramètresModes de passage des paramètres

• Teste de la procédure ModeParamDECLARE V_IN NUMBER := 1;V_OUT NUMBER :=2;V_INOUT NUMBER :=3;BEGINModeParam (V_IN, V_OUT, V_INOUT);DBMS_OUTPUT.PUT_LINE (‘V_IN : ‘ || V_IN);DBMS_OUTPUT.PUT_LINE (‘V_OUT : ‘ || V_OUT);DBMS_OUTPUT.PUT_LINE (‘V_INOUT : ‘ || V_INOUT);END;• Test du blocV_IN : 1V_OUT : 10V_INOUT : 9Procédure PL/SQL terminée avec succès

Page 79: Cours Plsql

79

Correspondance entre paramètres Correspondance entre paramètres Actuels et FormelsActuels et Formels

• Correspondance par position– Fournir des paramètres d’appel dans le même ordre que celui

des paramètres de définition du sous PG– Les paramètres avec DEFAULT doivent être les derniers pour

pouvoir ne pas leur fournir de valeurs• Correspondance par nom

– Permet de ne pas respecter l’ordre de définition– Utile pour des sous PG avec un nombre important de

paramètres

PROCEDURE CorrespondanceParam (P_A VARCHAR2, P_B NUMBER, P_C BOOLEAN, P_D DATE) as

BEGINNULL;-- ou un traitement quelconqueEND CorrespondanceParam;

Par position : CorrespondanceParam (V_A, V_B, V_C, V_D);

Par nom : CorrespondanceParam (P_A=>V_A, P_B=>V_B, P_C=>V_C, P_D=>V_D)

Page 80: Cours Plsql

80

FonctionsFonctionsUne fonction est un sous programme qui retourne une valeur

explicitement par la clause RETURN

• SYNTAXEFUNCTION nom_fonction [(paramètre [, paramètre…])]

RETURN type IS

/*déclarations si nécessaires*/

BEGINBEGIN

--instructions exécutables

--RETURN expression;

[EXCEPTIONEXCEPTION

--Gestionnaires d’exceptions]

ENDEND [nom_fonction] ;

• Le type de la fonction peut utiliser %TYPE

• Mêmes modes de passage de paramètres que les procédures

Page 81: Cours Plsql

81

FonctionsFonctions• ExempleLa fonction Avg_Sal retourne le salaire moyen des chercheurs d’un

laboratoireDECLAREDECLARE

--déclarations si nécessairesV_Sal_Moy NUMBER (10,3);FUNCTIONFUNCTION Avg_Sal (P_Labno IN Chercheur.Labno%TYPE)RETURN NUMBER ISV_Avg_Sal Chercheur.Sal%TYPE;BEGINBEGINSELECT AVG(Sal) INTO V_Avg_Sal FROM ChercheurWHERE Labno=P_Labno;RETURN V_Avg_Sal;EXCEPTIONEXCEPTIONWHEN OTHERS THEN RAISE_APPLICATION_ERROR (-20110, SUBSTR(SQLERRM, 1, 80));ENDEND AVG_SAL;

--autres déclarations

BEGINBEGINV_Sal_Moy := Avg_Sal (10);-- Appel fonctionDBMS_OUTPUT.PUT_LINE (‘Salaire Moyen :’|| V_Sal_Moy);

ENDEND;--fin bloc externe

Page 82: Cours Plsql

82

Exceptions dans les sous-programmes Exceptions dans les sous-programmes et Impact sur les paramètreset Impact sur les paramètres

• Dans un sous programme, une exception non traitée se reproduit selon le principe de propagation. En conséquence, les valeurs des paramètres formels ne seront pas récupérées dans les paramètres actuels

Page 83: Cours Plsql

83

Exceptions dans les sous-programmes Exceptions dans les sous-programmes et Impact sur les paramètreset Impact sur les paramètres

• ExempleDECLARE

PROCEDURE Proc_RaiseError (p_Raise IN BOOLEAN , p_Parameter OUT NUMBER) ASMy_Exception Exception;BEGIN

p_Parameter := 10; IF p_Raise THEN RAISE My_Exception; END IF;

END Proc_RaiseError;v_Temp NUMBER := 5;

BEGIN DBMS_OUTPUT.PUT_LINE('V_temp avant Premier appel : '||v_temp); Proc_RaiseError(FALSE, v_Temp); DBMS_OUTPUT.PUT_LINE('V_temp Après appel en succès:'||v_temp); v_Temp := 8; DBMS_OUTPUT.PUT_LINE('V_temp Avant second appel : '||v_temp); Proc_RaiseError(TRUE, v_Temp);EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('V_temp après second appel:'||v_temp);END;

V_temp avant Premier appel : 5V_temp Après appel en succès : 10V_temp Avant second appel : 8V_temp après second appel : 8

Page 84: Cours Plsql

84

Appels mutuels entre sous-Appels mutuels entre sous-programmesprogrammes

• Puisque les noms des sous programmes locaux sont des identificateurs, ils doivent être déclarés avant qu’ils soient utilisés. Par exemple, si un sous programme A appelle un sous programme B, B doit être déclaré avant A.

• Dans le cas de références mutuelles (A appelle B et B appelle A), il faut procéder à une déclaration en avant (forward) de l’un ou même des deux sous programmes selon l’utilisation

Page 85: Cours Plsql

85

Appels mutuels entre sous-Appels mutuels entre sous-programmesprogrammes

• ExempleDECLARE v_TempVal BINARY_INTEGER := 5; -- Forward declaration of procedure B. PROCEDURE B(p_Counter IN OUT BINARY_INTEGER); PROCEDURE A(p_Counter IN OUT BINARY_INTEGER) IS BEGIN IF p_Counter > 0 THEN B(p_Counter); p_Counter := p_Counter - 1; END IF; END A; PROCEDURE B(p_Counter IN OUT BINARY_INTEGER) IS BEGIN p_Counter := p_Counter - 1; A(p_Counter); END B;BEGIN B(v_TempVal);END;

Page 86: Cours Plsql

86

ExercicesExercices1. Ecrire un bloc PL/SQL qui appelle une fonction permettant de

sélectionner le plus grand numéro de département (DEPTNO) de la table DEPT et le stocke dans une variable SQL*Plus. Affichez le résultat à l’écran.

2. Ecrire un bloc PL/SQL qui appelle une procédure permettant de calculer le montant de la commission d’un employé donné, en fonction de son salaire. Si le salaire de l’employé est inférieur à 1OOO$, la commission vaut 10% du salaire. Si le salaire de l’employé est compris entre 1OOO$ et 1500$, la commission vaut 15% du salaire. Si le salaire de l’employé est supérieur à 15OO$, la commission vaut 20% du salaire. Si le salaire de l’employé est NULL, la commission vaut 0.

Page 87: Cours Plsql

87

ExercicesExercices

DECLAREV_deptno_Max Number;

FUNCTION Max_Dept

RETURN Number IS

V_deptno NUMBER ;BEGINBEGIN

SELECT MAX (deptno)INTO V_deptnoFROM dept;Return V_deptno;

EXCEPTIONEXCEPTION

WHEN NO_DATA_FOUND THENDBMS_OUTPUT.PUT_LINE (‘aucun département enregistré’);ENDEND Max_Dept;

BEGINV_deptno_Max := Max_Dept ;

DBMS_OUTPUT.PUT_LINE (V_deptno_Max);END ;

Page 88: Cours Plsql

88

ExercicesExercicesDECLARE PROCEDURE Calcul_Commission (P_empno emp.empno%TYPE) ISV_sal emp.sal%TYPE;V_comm emp.comm%TYPE; --peut être une variable globaleBEGINSELECT salINTO V_salFROM empWhere empno= P_empno;IF V_sal <1000 then V_comm:=V_sal*0.10;ELSIF V_sal Between 1000 and 1500 then V_comm:=V_sal*0.15;ELSIF V_sal > 1500 then V_comm:=V_sal*0.20;Else V_comm:=0;END IF;UPDATE empSET comm= V_comm;END Calcul_Commission;

BEGINCalcul_Commission (10);--appel de la procédure

END;

Page 89: Cours Plsql

89

PlanPlan

• Section 2 : Les sous-programmes stockés

1. Introduction2. Procédures stockées3. Fonctions stockées4. Suppression de sous programmes stockés5. Dictionnaire de données et sous-programmes stockés6. Sous-programmes stockés versus sous programmes

locaux7. Sous-programmes et privilèges

Page 90: Cours Plsql

90

IntroductionIntroduction

• La différence entre une procédure stockée et une procédure déclarée et utilisée dans un bloc anonyme est importante. Cette dernière est temporaire. C’est-à-dire qu’elle n’existe plus lorsque l’exécution du bloc anonyme est terminée

• Fonction ou Procédure stockée : sous programme (en tant qu’objet du dictionnaire Oracle) appelable par un utilisateur, directement ou indirectement

Page 91: Cours Plsql

91

PROCEDURES StockéesPROCEDURES Stockées• Syntaxe

CREATE [OR REPLACE] ProcedureOù

Procedure : syntaxe habituelle de déclaration d’une procédureOR REPLACE : Remplace une procédure existante (suppression + re-création)

• Exemple

CREATE OR REPLACE PROCEDURECREATE OR REPLACE PROCEDURE raise_salary (p_empno emp.empno%TYPE, p_montant Number) IS

V_sal_actuel emp.sal%type;E_sal_NULL EXCEPTION;BEGINBEGINSELECT sal INTO v_sal_actuel FROM empWHERE empno = p_empno and p_empno is not null;IF v_sal_actuel IS NULL THENRAISE E_sal_NULL;ELSEUPDATE emp SET sal = sal + p_montantWHERE empno = p_empno;END IF;EXCEPTIONEXCEPTION WHEN NO_DATA_FOUND THEN ….. WHEN E_sal_NULL THEN -- instructions exécutablesENDEND raise_salaryraise_salary;

SQL> EXECUTE raise_salary(7788, 1000);

Page 92: Cours Plsql

92

• Autres ExemplesCREATE OR REPLACE PROCEDURE Affiche_Sal_Moy CREATE OR REPLACE PROCEDURE Affiche_Sal_Moy

ISIS

V_avg_sal emp.sal%type ;V_avg_sal emp.sal%type ;

BEGINBEGIN

SELECT AVG(SAL) INTO v_avg_salSELECT AVG(SAL) INTO v_avg_sal FROMFROM EMPEMP ;;

DBMS_OUTPUT.PUT_LINE (concat (‘salaire Moyen : ‘,v_avg_sal);DBMS_OUTPUT.PUT_LINE (concat (‘salaire Moyen : ‘,v_avg_sal);

END;END;

SQL> EXECUTE affiche_sal_moy;

Salaire Moyen : 2073,21

CREATE OR REPLACE PROCEDURE Affiche_Sal_Moy_deptno (p_deptno dept.deptno%type) CREATE OR REPLACE PROCEDURE Affiche_Sal_Moy_deptno (p_deptno dept.deptno%type) ISIS

V_avg_sal emp.sal%type;V_avg_sal emp.sal%type;

BEGINBEGIN

SELECT AVG(SAL) INTO v_avg_salSELECT AVG(SAL) INTO v_avg_sal

FROM EMPFROM EMP

WHERE deptno = p_deptno AND p_deptno is not null;WHERE deptno = p_deptno AND p_deptno is not null;

DBMS_OUTPUT.PUT_LINE(‘salaire Moyen : ‘||v_avg_sal);DBMS_OUTPUT.PUT_LINE(‘salaire Moyen : ‘||v_avg_sal);

END;END;

SQL> EXECUTE Affiche_Sal_Moy_deptno(10);

salaire Moyen : 2916,67

PROCEDURES StockéesPROCEDURES Stockées

Page 93: Cours Plsql

93

• Autres Exemples

CREATE OR REPLACE PROCEDURE get_emp_name (p_empno CREATE OR REPLACE PROCEDURE get_emp_name (p_empno ININ emp.empno emp.empno%type, p_ename %type, p_ename OUTOUT emp.ename%type) emp.ename%type)

ISIS

BEGIN BEGIN

SELECT SELECT ename ename INTO INTO p_enamep_ename

FROM FROM emp emp

WHERE WHERE empno = p_empno and p_empno is not null; empno = p_empno and p_empno is not null;

EXCEPTION EXCEPTION

WHEN NO_DATA_FOUND ThenWHEN NO_DATA_FOUND Then

DBMS_OUTPUT.PUT_LINE (‘Employé non Trouvé);DBMS_OUTPUT.PUT_LINE (‘Employé non Trouvé);

END get_emp_name;END get_emp_name;

SQL> EXECUTE get_emp_name (7788);

‘SCOTT’

PROCEDURES StockéesPROCEDURES Stockées!!

Page 94: Cours Plsql

94

PROCEDURES StockéesPROCEDURES Stockées• CREATE PROCEDURE/FUNCTION

Compile et Stocke dans le Dictionnaire de Oracle

• La vue USER_ERRORS Affiche les erreurs de compilationSQL>SHOW ERRORS (commade SQL*Plus)

• La vue USER_OBJECTS Présente les objets-Oracle de chaque utilisateur

Name Null? Name Null? TypeType ------------------------------- -------- ------------------------ OBJECT_NAME VARCHAR2(128) OBJECT_ID NUMBER OBJECT_TYPE VARCHAR2(13) CREATED DATE STATUS VARCHAR2(7)

Page 95: Cours Plsql

95

PROCEDURES StockéesPROCEDURES Stockées

• La vue USER_SOURCEPrésente le code source des sous programmes de chaque utilisateur Name Null? Name Null? TypeType ------------------------------- -------- ------------------------ NAME NOT NULL VARCHAR2(30) TYPE VARCHAR2(12) LINE NOT NULL NUMBER TEXT VARCHAR2(2000)

Possibilité de récupérer le texte source d’1 sous programme stockée :

SELECT line, TextFROM USER_SOURCEWHERE UPPER(NAME) = ‘nom_sous_prog’AND UPPER(TYPE) = ‘FUNCTION’ORDER BY line ;

Page 96: Cours Plsql

96

PROCEDURES StockéesPROCEDURES Stockées

LINE TEXT

--------- ------------------------------------------------- 1 procedure get_emp_ename ( 2 p_empno in emp.empno%type, 3 p_ename OUT emp.ename%type) 4 is 5 begin 6 select ename 7 into p_ename 8 from emp 9 where empno = p_empno; 10 exception 11 when no_data_found then 12 dbms_output.put_line (‘employé non trouvé’); 13 end get_emp_name;

Page 97: Cours Plsql

97

FONCTIONS StockéesFONCTIONS Stockées

Doit retourner une valeur. CREATE [OR REPLACE] fonction

Où fonction : syntaxe habituelle de déclaration d’une fonction

• Exemple 1

CREATE OR REPLACE FUNCTION LIB_JOUR (p_date DATE) RETURN VARCHAR2 IS

BEGIN RETURN (TO_CHAR(p_date, ‘Day’));EXCEPTION

When Others Then RETURN (NULL);END;

V_Lib_Jour := Lib_Jour(sysdate) ; -- appel de la fonction

Page 98: Cours Plsql

98

FONCTIONS StockéesFONCTIONS Stockées• Exemple 2

CREATE OR REPLACE FUNCTION SECOND_SAL_DEPTNO (P_DEPTNO DEPT.DEPTNO%TYPE)

RETURN NUMBER IS/* DECLARATIONS */

CURSOR C_EMP (P_DEPTNO DEPT.DEPTNO%TYPE) IS SELECT SAL FROM EMP WHERE DEPTNO = P_DEPTNO and P_DEPTNO IS NOT NULL ORDER BY SAL;

V_SAL EMP.SAL%TYPE DEFAULT NULL;BEGINOPEN C_EMP(P_DEPTNO);LOOPFETCH C_EMP INTO V_SAL;EXIT WHEN C_EMP%NOTFOUND OR C_EMP%ROWCOUNT=2;END LOOP ;CLOSE C_EMP;

RETURN(V_SAL);END;

Page 99: Cours Plsql

99

FONCTIONS StockéesFONCTIONS Stockées• Exemple Find_GradeFind_Grade qui retourne le grade de salaire d’un empno

s’il existe,–1 , sinon.

SQL> CREATE OR REPLACE function Find_Grade Find_Grade (p_empno in emp.empno%type) 2 RETURN number 3 is 4 v_grade salgrade.grade%type; 5 begin 6 select grade 7 into v_grade 8 from emp, salgrade 9 where empno = p_empno and p_empno is not null 10 and sal between losal and hisal; 11 return (v_grade); 12 exception 13 when no_data_found then 14 return(-1); 15 end Find_grade; SQL> var H_grade number;SQL> execute :H_grade := find_grade(7788);--appel de la fonction SQL> print H_grade H_GRADE --------- 4

Page 100: Cours Plsql

100

Suppression de sous-programmes stockésSuppression de sous-programmes stockés

• Suppression d’une FONCTION/PROCEDUREDROP {PROCEDURE | FUNCTION} nompf ;

• Remarques1. CREATE et DROP : Commandes du LDD. !!!2. Modes de passage de paramètres identiques aux sous-

programmes non stockés.

Page 101: Cours Plsql

101

Sous-programmes stockés versus sous-Sous-programmes stockés versus sous-programmes locauxprogrammes locaux

• Comparaison S/Pg. stocké et S/Pg. local

Sous-Programme Stocké Sous-Programme Local

Stocké sous forme compilée : immédiatement exécutable

Compilé avec son bloc parent.Si le bloc est exécuté plusieurs fois, le sous-programme sera compilé à chaque fois

Appelable par tout blocUtilisateur ayant le privilège Exécute sur le sous programme

Appelable uniquement dans le bloc parent

.. ..

Page 102: Cours Plsql

102

Sous-programmes et privilegesSous-programmes et privileges

• Le privilège EXECUTE

Le propriétaire d’un s/pg stocké ou d’un package peut autoriser d’autres utilisateurs à s’en servir en leur accordant le privilège EXECUTE :

– GRANT EXECUTE ON {fonct | proc | pkg} TO username ;GRANT EXECUTE ON {fonct | proc | pkg} TO username ;

– SQL> SQL> GRANTGRANT EXECUTE ONEXECUTE ON Lib_Jour Lib_Jour TO BTO B;;

Page 103: Cours Plsql

103

Sous-programmes et privilegesSous-programmes et privileges

• Privilège Execute : Cas d’objets de même nom

Si UserB possède une table de même nom T1. Lorsque UserB appelle UserA.SOUSPROG, quelle table sera modifiée ? C’est UserA.T1. Ce concept peut être énoncé par la règle :Règle : Un s/pg s’exécute sous les privilèges de son propriétaire.

Page 104: Cours Plsql

104

Sous-programmes et RoleSous-programmes et Role

• Octroi de Privilèges sans ROLE

GRANT SELECT ON T2 TO UserB ;GRANT EXECUTE ON F TO UserB ;

permet à UserB de compiler avec succès son sous programme

Page 105: Cours Plsql

105

Sous-programmes et RoleSous-programmes et Role

GREATE ROLE My_Role;GRANT SELECT ON T2 TO My_Role;GRANT EXECUTE ON F TO My_Role;GRANT My_Role TO UserB ;ne marchera pas ; d’où  :Règle : Un s/pg s’exécute sous les privilèges attribués explicitement

(non à travers un ROLE) à son propriétaire

• Octroi de Privilège à travers un ROLE 

Page 106: Cours Plsql

106

PlanPlan

• Section 3 : Les packages

1. Structure d’un package2. Développement d’un package3. Le package DBMS_OUTPUT

Page 107: Cours Plsql

107

Structure d’un packageStructure d’un package

Progiciel, réunit des fonctions et des procédures stockéesComposé de 2 parties :

• Package Specification : déclarativevariables globales, Exceptions, curseurs, typesprototypes de fonctions et des procédures

• Package Body :Description complète des fonctions/procédures globales§ BEGIN optionnelle

Déclaré en 2 phases :

Page 108: Cours Plsql

108

Développement d’un packageDéveloppement d’un package

CREATE OR REPLACE PACKAGE pkg_nameAS -- Déclaration variables Globales, Exceptions, Curseurs

... -- Prototypes des Fonctions / Procédures Globales

prototype1;prototype2;...prototype n;

END [pkg_name];

Page 109: Cours Plsql

109

Développement d’un packageDéveloppement d’un package

CREATE OR REPLACE PACKAGE BODY pkg_nameAS -- Corps des Fonctions / Procédures Globales BEGIN -- optionnelleCommandes à exécuter une seule fois suite à votre premier appel du package(initialisation de variables par des valeurs calculées)END [pkg_name];

Page 110: Cours Plsql

110

Développement d’un packageDéveloppement d’un package

• Exemple CREATE OR REPLACE PACKAGE pkg_EMP AS

-- Déclaration variables Globales

G_nb_emp number(3);

G_nb_dept number(2);

G_nb_MANAGERS number(2);

G_avg_sal number;

-- Prototypes des Fonctions / Procédures Globales

function get_sal(p_empno in emp.empno%type) return emp.sal%type;

function get_grade(p_empno in emp.empno%type) return salgrade.grade%type;

function get_nb_emp_exceeds_avg_sal return number;

END pkg_EMP;

Page 111: Cours Plsql

111

Développement d’un packageDéveloppement d’un packageCREATE OR REPLACE PACKAGE BODY Pkg_EMP IS

Function get_sal (p_empno in emp.empno%type) return emp.sal%type ISv_sal number ;BEGINIF p_empno is not null THEN

RAISE NO_DATA_FOUND; -- ou une exception utilisateurEND IF;select sal into v_sal

from empwhere empno =p_empno;

return v_sal;EXCEPTION when no_data_found then

raise_application_error ( -20000, ‘N° Employé ' || p_empno || ' Non Trouvé ou non renseigné');

return null;END get_sal;

Page 112: Cours Plsql

112

Développement d’un packageDéveloppement d’un package

Function get_grade(p_empno in emp.empno%type) return salgrade.grade%type ISv_grade salgrade.grade%type;BEGIN

select grade into v_gradefrom emp , salgradewhere empno = p_empno and p_empno is not nulland sal between losal and hisal;

return v_grade;EXCEPTIONwhen no_data_found then

raise_application_error (-20001,'Grade de Salaire non trouvé pour Employé n° '||

p_empno); return null;END get_grade;

Page 113: Cours Plsql

113

Développement d’un packageDéveloppement d’un package

Function get_nb_emp_exceeds_avg_sal Return number ISv_nb integer;BEGIN

select count(*) into v_nbfrom emp where sal > G_avg_sal;

return v_nb; -- utilisation var GlobaleEXCEPTION when no_data_found then

raise_application_error (-20001, 'Erreur '); return null;END get_nb_emp_exceeds_avg_sal ;

Page 114: Cours Plsql

114

Développement d’un packageDéveloppement d’un package

BEGIN -- Initialiser la variable G_nb_emp

select count(*) into G_nb_empfrom emp;

-- Initialiser la variable G_nb_deptselect count(*) into G_nb_dept

from dept;-- Initialiser la variable G_nb_MANAGERS

select count(*) into G_nb_MANAGERSfrom empwhere upper(job) = 'MANAGER';

-- Initialiser la variable G_avg_salselect avg(sal) into G_avg_salfrom emp;

END pkg_EMP;

Page 115: Cours Plsql

115

Développement d’un packageDéveloppement d’un package

• Intérêt des packages ./. à des sous programmes stockés :

• A la première utilisation du package, tous ses composants seront chargés en mémoire pour être directement disponibles, cette technique améliore les temps de réponse comparativement à l’usage de sous programmes stockés où chacun est cherché individuellement sur demande.

Page 116: Cours Plsql

116

APPEL des s/pg d’un packageAPPEL des s/pg d’un package

Préfixer par le nom du package.ExempleExempleBEGINDBMS_OUTPUT.PUT_LINE (‘Salaire : ‘ ||PKg_emp.get_sal(7788) );END;ouExecute :h_sal := PKg_emp.get_sal(7788);Les variables globales du package peuvent être référencées :BEGINDBMS_OUTPUT.PUT_LINE ('G nb dept : ' ||PKg_emp.g_nb_dept );END;

Page 117: Cours Plsql

117

PlanPlan

Chapitre 5 : Déclencheurs de BD

1. Introduction2. Utilité des déclencheurs3. Caractéristiques des déclencheurs4. Description d’un déclencheur5. Usage Des Prédicats de Déclencheurs :

INSERTING, UPDATING et DELETING 6. Gestion des déclencheurs

Page 118: Cours Plsql

118

IntroductionIntroduction

• On appelle déclencheur (trigger) un traitement qui se déclenche suite à un événement

• Dans une programmation traditionnelle se faisait par un appel de sous programme

• Il existe deux types de déclencheurs :

– Des déclencheurs applicatifs crées et manipulés au niveau d’une application

– Des déclencheurs de bases de données stockés dans le dictionnaire de données du SGBD et associés à des événements sur des tables

Page 119: Cours Plsql

119

Utilité des déclencheursUtilité des déclencheurs

• Les déclencheurs sont utiles pour plusieurs fins :

– Implémenter certaines règles de métier du SI de l’organisation (par exemple, MAJ du stock suite à une entrée, déclenchement d’une demande de réapprovisionnement à la suite d’une insuffisance de stock,…)

– Mettre en oeuvre une politique de sécurité complexe (par exemple, interdire des modifications des données à certains utilisateurs, garder trace mises à jour douteuses,….

Page 120: Cours Plsql

120

Caractéristiques des déclencheursCaractéristiques des déclencheurs

• Les Triggers ressemblent aux sous programmes stockés sur les points suivants :

– Sont des blocs PL/SQL nommés

– Objets stockés dans Oracle sous forme de code source et p-code (exécutable)

• Mais ils en diffèrent sur les points suivants :

– Liés à un événement : exécution implicite

– Ne sont pas paramétrables

– Peuvent être désactivés

– Etc.

Page 121: Cours Plsql

121

Description d’un déclencheurDescription d’un déclencheur

Elément Valeurs possibles

Explication

Nom_Trigger Choisie par le développeur

Identifiant du déclencheur

Nom_Table Nom d’une table La table sur laquelle le trigger est défini. Si l’événement est exécuté sur cette table, le trigger sera déclenché

Evénement INSERT ou UPDATE, ou DELETE

Evénement déclenchant l’exécution du trigger : commande LMD ou une combinaison utilisant OR

Séquencement BEFORE ou AFTER Caractérise le séquencement du déclencheur (timing) par rapport à son événement. Avec BEFORE (AFTER), le déclencheur est lancé avant (après) que l’événement déclenchant ne soit exécuté.

• Eléments de description

Un trigger est défini à travers les éléments suivants :

Page 122: Cours Plsql

122

Description d’un déclencheurDescription d’un déclencheur

• Niveaux de déclenchement

Il existe deux niveaux de déclenchement :

1. Niveau instruction (statement level trigger)

2. Niveau ligne (row level trigger)

(1) : un déclencheur de niveau 1 s’exécute une seule fois

Création : la commande de création d’un déclencheur permet sa compilation et son stockage dans la métabase. Après une compilation correcte, le déclencheur est crée à l’état actif (ENABLE)

Page 123: Cours Plsql

123

Description d’un déclencheurDescription d’un déclencheur

• Création d’un TRIGGER

CREATE [ OR REPLACE ] TRIGGER nom_Trigger

{ BEFORE | AFTER } événement

ON nom_Table

DECLARE

-- déclarations variables, curseurs, records,…

BEGIN

- - traitement

EXCEPTION

- - Gestionnaires d’exceptions

END [nom_Trigger ];

Page 124: Cours Plsql

124

Description d’un déclencheurDescription d’un déclencheur• Déclencheur de Niveau ligne (row level trigger)

Un déclencheur de ligne s’exécute une fois pour chaque n-uplet affecté par l’événement déclanchant.

• Création d’un TRIGGERCREATE [OR REPLACE] TRIGGER nom_Trigger

{ BEFORE | AFTER } événement

ON nom_Table

FOR EACH ROW [WHEN condition]

[REFERINCING {[old [AS] nom_old] | New [AS] nom_new]}]

DECLARE

-- déclarations variables, curseurs, records,…

BEGIN

- - traitement

EXCEPTION

- - Gestionnaires d’exceptions

END [nom_Trigger ];

Page 125: Cours Plsql

125

Description d’un déclencheurDescription d’un déclencheur

For each row Clause optionnelle, si utilisée le déclencheur spécifié sera de niveau ligne. Autrement il est de niveau instruction

Condition Option de la clause For each Row (valable uniquement pour les triggers de niveau ligne), introduit une condition selon laquelle le corps du déclencheur peut être exécuté ou simplement abandonné

Referencing Permet de changer les noms standards des pseudo records OLD et NEW par de nouveaux noms nom_old et nom_new

Page 126: Cours Plsql

126

Description d’un déclencheurDescription d’un déclencheur

• Exemples1. Ecrire un trigger de BD qui affiche un message à la suite de la

suppression d’un dept

Choix des composants du trigger

Nom Evénement Séquencement Niveau Table

TRG_DEL_DEPT DELETE BEFORE(ou AFTER)

Ligne DEPT

Page 127: Cours Plsql

127

Description d’un déclencheurDescription d’un déclencheur

CREATE OR REPLACE TRIGGER TRG_DEL_DEPT

AFTER DELETE -- ou bien BEFORE

ON DEPT

FOR EACH ROW -- de niveau n-uplet

BEGIN

DBMS_OUTPUT.PUT_LINE(‘TRG0 : Dépt supprimé’);

END TRG_DEL_DEPT;

Test :

SQL> delete from dept

where deptno NOT IN (Select deptno from emp);

TRG0 : Dépt supprimé

1 ligne(s) supprimée(s).

Page 128: Cours Plsql

128

Description d’un déclencheurDescription d’un déclencheur• Remarques

– Comme il s’agit d’un ‘Row level Trigger’ le corps du déclencheur sera exécuté avec chaque n-uplet affecté par l’événement déclenchant (DELETE). Si aucune ligne n’est affectée alors aucun message affiché

– Utiliser un trigger de niveau instruction pour exécuter le corps du déclencheur une seule fois quelque soit le nombre de lignes affectées (même 0). Si aucune ligne n’est affectée alors le message sera affiché.

Page 129: Cours Plsql

129

Description d’un déclencheurDescription d’un déclencheur

• Exemple de Trigger de niveau instruction CREATE OR REPLACE TRIGGER TRG_DEL_DEPT_Niv_Ins

AFTER DELETE -- ou bien BEFORE

ON DEPT

BEGIN

DBMS_OUTPUT.Put_Line(‘TRG_DEL_DEPT_Niv_Ins Déclenché’);

END TRG_DEL_DEPT_Niv_Ins;

Test du trigger :

SQL> delete from dept where

deptno is null;

TRG_DEL_DEPT_Niv_Ins Déclenché

0 ligne(s) supprimée(s).

Page 130: Cours Plsql

130

Description d’un déclencheurDescription d’un déclencheur

• Les Pseudo-records  : old et : new

• Un trigger de niveau ligne se déclenche une fois avec chaque n-uplet traité par l’événement du trigger

• A l’intérieur d’un trigger de niveau ligne, on a souvent besoin d’accéder aux données du n-uplet en cours de manipulation. PL/SQL le permet par le biais des 2 pseudo-records :old et :new de même structure que la table sur laquelle le trigger est défini.

Page 131: Cours Plsql

131

Description d’un déclencheurDescription d’un déclencheur

• Non valables pour les triggers de niveau instruction.

• Utilisables dans les curseurs implicites et explicites.

Evénement OLD NEW

INSERT Tous les champs sont nulls Valeurs à insérer en provenance de la commande INSERT qui a déclenché le trigger

UPDATE Valeurs originales du n-uplet avant UPDATE

Nouvelles valeurs après UPDATE

DELETE Valeurs Originales du n-uplet avant DELETE

Page 132: Cours Plsql

132

Description d’un déclencheurDescription d’un déclencheur

• Exemple 1. Ecrire un trigger qui enregistre dans la table ARCHIVE_DEPT

chaque dept. Supprimé.

CREATE OR REPLACE TRIGGER TRG_Archive_Dept BEFORE DELETE ON DEPTFOR EACH ROWBEGIN INSERT INTO ARCHIVE_DEPT (DEPTNO, Dname, Loc)VALUES (:old.deptno, :old.dname, :old.loc);EXCEPTION

When OTHERS THENRAISE_APPLICATION_ERROR(-20001,’Erreur dans Trigger Before

Delete On DEPT’) ;END TRG_Archive_Dept;

Nom Evénement Séquencement Niveau Table

TRG_Archive_Dept DELETE BEFORE Ligne DEPT

Page 133: Cours Plsql

133

Description d’un déclencheurDescription d’un déclencheur• ExempleEcrire un trigger de BD qui à la suite d’une modification de salaire enregistre dans la

table AUDIT_SAL (Utilisateur, date_maj, Empno, anc_sal, nouv_sal)

CREATE OR REPLACE TRIGGER TRG_Audit_Sal AFTER UPDATE OF SAL ON EMPFOR EACH ROWBEGIN INSERT INTO AUDIT_SAL VALUES (user,sysdate, :old.empno, :old.sal, :new.sal);EXCEPTION

When others then null;END ;

SQL> update emp set sal= sal + 1000 where deptno= 10;

3 ligne(s) mise(s) à jour.

SQL> select * from audit_sal;

UTILISATE DATEMAJ EMPNO ANC_SAL NOUV_SAL--------- -------- --------- --------- ---------SCOTT 18/04/02 7782 2450 3450SCOTT 18/04/02 7839 5000 6000SCOTT 18/04/02 7934 1300 2300

Page 134: Cours Plsql

134

Description d’un déclencheurDescription d’un déclencheur• La clause WHEN «condition»

Cette clause est valide uniquement pour les row-level triggers. Si utilisée, la condition sera évaluée pour chaque ligne affectée par l’événement du trigger, et le corps du trigger n’est exécuté pour cette ligne que si l’expression logique est vraie.

• Les pseudo-record old et new sont autorisés dans la clause WHEN mais sans le préfixe (:)

Page 135: Cours Plsql

135

Description d’un déclencheurDescription d’un déclencheur• Exemple 1

CREATE OR REPLACE TRIGGER TRG_B_IU_EMP BEFORE INSERT OR UPDATE of deptno ON EMPFOR EACH ROW WHEN (new.deptno = 40)BEGIN

Update dept Set nb_emp = nvl(Nb_emp,0) + 1Where deptno = :new.deptno;

END TRG_B_U_EMP;

Test du trigger :SQL> update emp

set deptno = 40 where deptno = 10;

3 ligne(s) mise(s) à jour.SQL> select * from dept where deptno = 40; DEPTNO DNAME LOC NB_EMP--------- -------------- ------------- --------- 40 OPERATIONS BOSTON 3

Page 136: Cours Plsql

136

Description d’un déclencheurDescription d’un déclencheur• Exemple 2Modification systématique de la commission pour la fonction SALESMAN :

Augmenter leur commission au prorata de leur augmentation du salaire.CREATE OR REPLACE TRIGGER TRG_B_Usal BEFORE UPDATE OF SAL ON EMPFOR EACH ROW WHEN (upper(new.job) = ‘SALESMAN’)BEGIN IF nvl(:old.sal,0)>0 THEN :new.comm := :old.comm *(:new.sal/:old.sal);END IF;END TRG_B_Usal;

Test du trigger :EMPNO SAL COMM JOB--------- --------- ---------- ---------7499 1600 300 SALESMAN

UPDATE EMPSET SAL = SAL+320 -- 320 = 20% de salWHERE EMPNO = 7499;

EMPNO SAL COMM--------- --------- --------- 7499 1760 360

Page 137: Cours Plsql

137

Description d’un déclencheurDescription d’un déclencheur• Remarques :

– La clause WHEN condition équivaut un test portant sur tout le corps du trigger

– Ainsi, TRG_B_UI_EMP peut être réécrit comme suit :

CREATE OR REPLACE TRIGGER TRG_B_IU_EMP BEFORE INSERT OR UPDATE of deptno ON EMPFOR EACH ROW BEGIN IF (:new.deptno = 40) THEN

/* corps du trigger */END IF;END TRG_B_U_EMP;

Page 138: Cours Plsql

138

Description d’un déclencheurDescription d’un déclencheur• ExempleInterdire les modifications sur la table EMP en dehors des

horaires de travail supposés entre 8h à 17h.

CREATE OR REPLACE TRIGGER TRG_Grant_Emp BEFORE UPDATE ON EMPDECLARE

E_ACCES_DENIED EXCEPTION ;BEGIN If (to_number (to_char(sysdate,’HH24’) ) NOT between 8 and 17) THENRAISE E_ACCES_DENIED ;End IF ;EXCEPTIONWHEN E_ACCES_DENIED THENRAISE_APPLICATION_ERROR (-20001, ’Accès interdit en dehors des

horaires de travail’) ;END;

Page 139: Cours Plsql

139

Usage Des Prédicats de Déclencheurs : Usage Des Prédicats de Déclencheurs : INSERTING, UPDATING, et DELETINGINSERTING, UPDATING, et DELETING

• Si l’événement d’un trigger utilise OR, le trigger se déclenchera alors par l’une ou l’autre des commandes LMD. Les trois prédicats ci-dessus permettent de déterminer laquelle des opérations a déclenchée le trigger. On peut alors tester dans le corps du trigger :

CREATE OR REPLACE TRIGGER TRG_ARV_DEPT BEFORE INSERT OR DELETE OR UPDATE ON DEPT FOR EACH ROWDECLARE v_Operation CHAR(1);BEGIN IF INSERTING THEN v_Operation:= 'I'; ELSIF UPDATING THEN v_Operation:= 'U'; ELSE v_Operation:= 'D'; END IF;INSERT INTO Arch_dept (operation, changed_by, timestamp, old_deptno, old_dname,

old_loc,new_deptno, new_dname,new_loc) VALUES (v_Operation, USER, SYSDATE, :old.deptno, :old.dname, :old.loc, :new.deptno, :new.dname, :new.loc);

END TRG_ARV_DEPT;

Page 140: Cours Plsql

140

Usage Des Prédicats de Déclencheurs : Usage Des Prédicats de Déclencheurs : INSERTING, UPDATING, et DELETINGINSERTING, UPDATING, et DELETING

Test du Trigger :

insert into dept values (70,'gestion','FSEGS');update dept set dname = upper (dname)where deptno =70;select * from arch_dept;

C CHANGED_ TIMESTAM OLD_DEPTNO OLD_DNAME OLD_LOC NEW_DEPTNO NEW_DNAME NEW_LOC- -------- -------- ---------- ------------ ---------- ---------- ------------ ---------I SCOTT 18/04/02 70 gestion FSEGSU SCOTT 18/04/02 70 gestion FSEGS 70 GESTION FSEGSD SCOTT 18/04/02 70 GESTION FSEGS

Page 141: Cours Plsql

141

Gestion des déclencheursGestion des déclencheurs• DROP TRIGGER triggerName ;

• Activation / Désactivation d’un trigger

Parfois il est préférable de désactiver un trigger que de le supprimer en vue de le réactiver ultérieurement.

• ALTER TRIGGER triggerName { ENABLE |DISABLE } ;

A la création un trigger est activé

Un trigger désactivé (DISABLE) continue à exister dans le DD.

• Affichage des erreurs de compilation

SQL>SHOW ERRORS

• Activation/Désactivation de Tous les Triggers d’une table

ALTER TABLE TableName { ENABLE | DISABLE } ALL TRIGGERS ;

Page 142: Cours Plsql

142

ConclusionConclusion• Lorsqu’un trigger échoue (exception non traitée ou

explicitement reconduite avec RAISE_APPLICATION_ERROR sa commande événement Echoue de même.

• ExempleEcrire un déclencheur qui Interdit la suppression d’employés.

CREATE OR REPLACE TRIGGER TRG_DENY_DELETE_EMP BEFORE DELETE ON EMPDECLARE

E_DELETE_DENIED EXCEPTION ;BEGIN

RAISE E_DELETE_DENIED;EXCEPTIONWHEN E_DELETE_DENIED THENRAISE_APPLICATION_ERROR (-20002, 'Suppression d''Employées Non Autorisée') ;END;

Page 143: Cours Plsql

143

Merci de Votre attention