Conception Et Réalisation (Oracle) by Grare Stéphane - HTML preview

PLEASE NOTE: This is an HTML preview only and some elements such as links or page numbers may be incorrect.
Download the book in PDF, ePub, Kindle for a complete version.

Principe de fonctionnement

Les étapes suivantes montrent comment un déclencheur AFTER est lancé lors d’un

évènement sur la table ou il est défini.

Cas 1 : évènement INSERT

· Une instruction INSERT est exécutée sur une table comportant un déclencheur INSERT.

· L’instruction INSERT est journalisée dans le journal des transactions le record NEW reçoit la

copie de la ligne ajoutée à la table.

· Le déclencheur est lancé et ses instructions s’exécutent.

Cas 2 : évènement DELETE

· Une instruction DELETE est exécutée sur une table comportant un déclencheur DELETE.

· L’instruction DELETE est journalisée dans le journal des transactions le record OLD reçoit la

copie de la ligne supprimée de la table.

· Le déclencheur est lancé et ses instructions s’exécutent.

Cas 3 : évènement UPDATE

· Une instruction UPDATE est exécutée sur une table comportant un déclencheur UPDATE.

· L’instruction UPDATE est journalisée dans le journal des transactions sous la forme INSERT

et DELETE le record OLD reçoit la copie de la ligne de la table représentant l’image avant la

modification. Le record NEW reçoit la copie de la ligne de la table représentant l’image après

la modification.

· Le déclencheur est lancé et ses instructions s’exécutent.

Exemple : Création d’un déclencheur AFTER Vente_Insert sur l’instruction

INSERT de la table Ventes de structure

VENTES (vnt_art, vnt_cli, vnt_qte, vnt_prix)

Lorsqu’une ligne est insérée dans la table Ventes, le déclencheur décrémente la colonne

quantité en stock dans la table ARTICLES de la quantité vendue ;

ARTICLES (art_num, art_nom, art_coul, art_pa, art_pv, art_qte, art_frs)

CREATE TRIGGER Vente_Insert

AFTER INSERT

ON Ventes

For each row

152

index-153_1.png

BEGIN

UPDATE Article SET Art_Qte = Art_Qte – :new.Vnt_Qte

Where article.Art_Num. = :new.Vnt_Art

END ;

Dans l’exemple ci-dessus, le record new contient la ligne de Ventes qui vient d’être ajoutée,

et les colonnes de la table Vente sont manipulables à travers le record news. Un déclencheur

peut être défini avec l’instruction IF UPDATE, qui contrôle la mise à jour d’une colonne

donnée.

Les déclencheurs INSTEAD OF

Le principe de fonctionnement des déclencheurs INSTEAD OF est simple : l’instruction

appelante est interceptée, donc non réellement exécutée, et le code du déclencheur la

remplace : Il est ainsi possible de tester les valeurs insérées, mises à jour ou supprimées

pour décider de la suite des opérations.

Les déclencheurs INSTEAD OF peuvent être définis sur des vues : Un déclencheur sur une

vue permet d’étendre la possibilité de mie à jour de vues multi tables. Un seul déclencheur

INSTEAD OF par instruction est autorisé sur une table ou vue.

Exemple 1 : Trigger sur un événement de suppression (insteadOf). Pour les besoins de notre

exemple, on effectue les requêtes suivantes :

-- Test de suppression logique

create table personne (idp number, nom varchar(50), suppression number);

create view personneView as select * from personne;

insert into personne values (1,'pierre',0);

insert into personne values (2,'paul',0);

insert into personne values (3,'jacques',0);

Créons maintenant le trigger « supPersonne ».

153

index-154_1.png

index-154_2.png

Voici le code complet de notre trigger.

CREATE OR REPLACE TRIGGER supPersonne

INSTEAD OF DELETE

ON PersonneView

FOR EACH ROW

BEGIN

UPDATE personne

SET suppression = 1

WHERE idp = :old.idp;

END supPersonne;

Pour le tester, effectuons la requête suivante :

-- Une fois le trigger mis en place, le delete sera fait sur la vue

delete personneView where idp = 1;

Maintenant, si on affiche les données dans la vue, on constate avoir effectué une suppression

sur la personne ayant un id à 1.

154

Exemple 2 : Création d’un déclencheur INSTEAD OF Insert_Multiple sur l’instruction

INSERT de la vue multi tables, Vue_TousClients qui regroupent les clients français et

étrangers. Lorsqu’une ligne est insérée, le déclencheur met à jour les tables concernées.

ClientsF et ClientsE.

CREATE TRIGGER Insert_Multiple

INSTEAD OF INSERT

ON Vue_TousClients

FOR EACH ROW

BEGIN

If (select payC from new) = 'F'

Insert ClientsF select * from new

ELSE

Insert ClientsE select * from new

END

Trigger sur le schéma

On veut garder la trace des événements qui se sont produits sur le schéma (create, alter ...).

On crée la table qui stockera l’information :

create table auditDDL (

d date,

osUser varchar2(255),

curUser varchar2(255),

host varchar2(255),

owner varchar2(30),

typ varchar2(30),

nom varchar2(30),

sysevent varchar2(30));

Et on crée le trigger « trDDL ».

create or replace trigger trDDL

after ddl on schema

begin

if (ora_sysevent='TRUNCATE') or (ora_sysevent='DROP')

then null;

else

insert into auditDDL(d, osUser,curUser,host,owner,typ,nom,sysevent)

values(

sysdate,

sys_context('USERENV','OS_USER') ,

sys_context('USERENV','CURRENT_USER') ,

sys_context('USERENV','HOST') ,

ora_dict_obj_owner,

ora_dict_obj_type,

ora_dict_obj_name,

ora_sysevent );

end if;

155

index-156_1.png

end;

L’action suivante revient à la même que si vous cliquez sur la petite disquette pour

enregistrer. À noter que la compilation permet de détecter les éventuelles erreurs. Cliquez

droit et « Compiler » sur le code.

Pour tester notre trigger, exécutons les requêtes suivantes :

-- les requêtes create et alter sont stockées dans auditDDL

create table produit2 (idProd number, nomProd varchar(50));

alter table produit2 add constraint PKProd primary key (idProd);

-- la requête drop n'est pas stockée

drop table produit2;

Enfin, vérifions notre table « auditDLL » qui a dû lister les opérations effectuées :

156

index-157_1.png

index-157_2.png

index-157_3.png

select * from auditDDL;

Le débogage dans « Oracle SQL Developer »

« Oracle SQL Developer » prend également en charge le débogage de PL / SQL des bases

de données Oracle. Nous allons effectuer un exemple de débogage à partir d’un déclencheur

précédemment créé. Cliquez droit sur le déclencheur « LST_COMMANDES » puis

« Modifier ».

Pour aider au débogage, les numéros de ligne peuvent être ajoutés à la fenêtre Code. Cliquez

droit sur la marge et « Activer / désactiver les numéros de ligne ».

Les numéros de lignes s’affichent alors :

157

index-158_1.png

index-158_2.png

index-158_3.png

Vous pouvez définir un point d’arrêt en cliquant dans la marge, au niveau de la ligne ou vous

souhaitez positionner un point d’arrêt. Pour cela, cliquer droit sur la ligne concernée puis

« Activer / désactiver le point d’interruption ».

Après avoir sélectionné l’option, votre point d’arrêt s’affiche.

Cliquez sur l'icône « Debug ».

158

index-159_1.jpg

index-159_2.png

Un écran de débug s’affiche alors. Cliquez sur « Ok ».

Le débogueur doit s'arrêter à la ligne où vous avez placé le point d'arrêt. Vous pouvez

maintenant contrôler le flux d'exécution, modifier les valeurs des variables et des fonctions de

débogage…

159

index-160_1.jpg

index-160_2.png

index-160_3.png

Pour aller à la ligne suivante, cliquez sur le bouton suivant :

D’autres options sont disponibles comme « Exécuter jusqu’au curseur » en cliquant droit

sur la ligne correspondante.

Vous voyez les valeurs des champs dans l’onglet « Données ».

160

index-161_1.png

index-161_2.png

Cliquez sur « reprise » pour poursuivre.

161

FAQ

Comment compter le nombre d'occurrences dans une chaîne sans l'aide d'une

boucle itérative ? En utilisant les fonctions LENGTH() et REPLACE() de la façon suivante :

CREATE OR REPLACE FUNCTION CPT_OCCURRENCES

(

PC$Entree IN VARCHAR2, -- chaîne en entrée

PC$Recherche IN VARCHAR2 -- Chaîne à rechercher

) RETURN PLS_INTEGER IS

BEGIN

RETURN ( (LENGTH(PC$Entree) -

LENGTH(REPLACE(PC$Entree,PC$Recherche,NULL)) ) /

NVL(LENGTH(PC$Recherche),1) ) ;

END;

Testons notre fonction :

SELECT CPT_OCCURRENCES( 'le et le et le', 'le' ) "Nombre d'occurrences"

FROM DUAL ;

Comment savoir si une chaîne de caractères correspond à un nombre ? Plutôt que de

coder une fonction qui traite tous les cas de figure correspondant aux différents formats que

peut prendre un nombre (entier, nombre à virgule, nombre avec exposant...), il vaut mieux

laisser Oracle gérer la conversion et nous signaler s'il a rencontré une erreur comme dans la

fonction suivante :

create or replace function isNumeric(x in varchar2) return number as

-- renvoie 1 si le paramètre correspond à un nombre

-- 0 sinon

nb number;

begin

nb := to_number(x);

return 1;

exception

when others then

return 0;

end;

Exemple d'utilisation : Si la colonne X correspond à un nombre, on veut avoir ce nombre

multiplié par 1000 :

SELECT x,

isNumeric(x),

CASE

WHEN isNumeric(x) = 1 THEN 1000 * TO_NUMBER(x)

END x_fois_1000

FROM TEST;

162

index-163_1.png

Comment vérifier si une chaîne vérifie un certain format ? Pour vérifier qu'une chaîne

de caractère vérifie un format donné, on peut utiliser, à partir d'Oracle 10g, la fonction

MATCH du OWA_PATTERN qui permet de manipuler des expressions régulières. Cette

fonction retourne un booléen indiquant si le format est vérifié ou pas; elle ne peut donc être

appelée qu'en PL/SQL. Par exemple, pour vérifier que les numéros de téléphone en base

suivent le format français sur 10 chiffres avec comme séparateur des tirets, on peut faire :

Les expressions régulières peuvent utiliser les symboles suivants :

•^ : Début de la ligne

•$ : Saut de ligne ou fin de ligne

•\n : Saut de ligne

•. : Tout caractères sauf le saut de ligne

•\t : Tabulation

•\d : Chiffre (équivalent à [0-9])

•\D : Tout caractère sauf un chiffre (équivalent à [not 0-9])

•\w : Tout caractère alphanumérique (chiffres, lettres, _)

•\W : Tout caractère sauf un caractère alphanumérique

•\s : Tout espace (espace, tabulation, saut de ligne)

•\S : Tout caractère sauf un espace

•\b : Délimiteur de mots (entre un caractère qui vérifie \w et un autre qui vérifie \W)

•\xnn : Caractère dont le code ascii est en hexadécimal nn

•\nnn : Caractère dont le code ascii est en octal nnn

Les éléments ci-dessus peuvent être suivis par les indicateurs de cardinalité suivants :

•? : 0 ou 1 occurrence

•* : 0 ou plus occurrences

•+ : 1 ou plus occurrences

•{n} : Exactement n occurences

•(n,} : Au moins n occurences

•{n,m} : Entre n et m occurrences

163

L'expression régulière qu'on a utilisée pour décrire notre format de numéro de téléphone

^\d{2}-\d{2}-\d{2}-\d{2}-\d{2}$ se décrypte donc de la manière suivante :

•\d{2} : On cherche deux chiffres

•- : Suivis d'un tiret

•\d{2}- : Suivi de deux chiffres et d'un tiret

•\d{2}- : Suivi de deux chiffres et d'un tiret

•\d{2}- : Suivi de deux chiffres et d'un tiret

•\d{2} : Suivi de deux chiffres

Comme notre expression régulière commence par ^, elle décrit le début de la chaîne; comme

elle se termine par $, elle décrit aussi sa fin.

Comment générer un fichier de trace pour une session en cours ? Quand une

procédure est en cours d'exécution, il est possible de générer un fichier de trace (pour

exploitation par TkProf par exemple) en utilisant la routine set_sql_trace_in_session du

package DBMS_SYSTEM. Les paramètres de cette routine sont les suivants :

• SID : Identifiant de la session en provenance de V$SESSION

• SERIAL# : Second identifiant de la session en provenance de V$SESSION

• TRACE : Booléen. Il faut entrer TRUE pour demander à Oracle de générer le fichier de trace,

et FALSE pour arrêter sa génération.

Comment convertir une valeur hexadécimale en valeur décimale ? Simplement grâce à

la fonction TO_NUMBER : En voici un exemple d'utilisation.

SELECT

TO_NUMBER('ff','XXXXXXXX'),TO_NUMBER('fff','XXXXXXXX'),TO_NUMBER('ffff','XX

XXXXXX') from dual;

Comment crypter mon code ? Il est parfois nécessaire, lors du déploiement de vos

applicatifs, de crypter votre code afin de le protéger : il suffit pour cela de sauvegarder votre

code sous forme de fichiers sql et d'utiliser le programme « wrap.exe », se trouvant dans le

répertoire {Oracle_Home}\Bin\.

Le programme wrap accepte les 2 arguments suivants :

• iname : Nom du fichier en entrée

• oname : Nom du fichier de sortie

Voici un exemple avec le fichier suivant :

CREATE OR REPLACE FUNCTION debut

(PC$Chaine IN VARCHAR2) RETURN VARCHAR2 IS

BEGIN

RETURN SUBSTR( PC$Chaine, 1, 5 ) ;

END;

Encryptons-le :

...\BIN> wrap iname=c:\temp\debut.pls oname=c:\temp\debut.plb

164

PL/SQL Wrapper: Release 10.2.0.1.0- Production on Dim. Oct. 15 23:52:50

2006

Copyright (c) 1993, 2004, Oracle. All rights reserved.

Processing c:\temp\debut.pls to c:\temp\debut.plb

Vous pouvez ouvrir le nouveau fichier pour vérifier son contenu.

Attention, prenez évidemment soin de sauvegarder vos sources, cette procédure est bien

entendu irréversible ! Vous pouvez (devez) également vérifier que la compilation s'effectue

correctement :

@c:\temp\debut.plb

Attention, ceci ne fonctionne pas sur les triggers ou les blocs PL/SQL anonymes.

165

index-166_1.png

index-166_2.png

index-166_3.png

index-166_4.png

index-166_5.png

index-166_6.png

index-166_7.png

index-166_8.png

index-166_9.png

index-166_10.png

index-166_11.png

index-166_12.png

index-166_13.png

index-166_14.png

index-166_15.png

index-166_16.png