Chapitre Interfaces de Programmation 1. TRIGGER
Transcription
Chapitre Interfaces de Programmation 1. TRIGGER
BASE DE DONNEES – 2d Cycle Chapitre Interfaces de Programmation 1. TRIGGER 1.1. Définition du ‘trigger’ = ‘reflexe’ = ‘déclencheur’ C’est une procédure cataloguée dans la base de données, dont l’exécution est déclenchée par l’occurrence de l’événement associé au trigger. Cet événement survient à la suite de conditions particulières : - opération de mise à jour d’une table, d’un tuple - passage à vrai d’une condition sur une ou plusieurs valeurs de données - combinaison d’une occurrence d’opération de mise à jour et d’une condition sur valeur de données Le trigger est un moyen de prendre en compte dans le SGBDR, des contraintes sémantiques complexes que la clause CHECK ne permet pas de déclarer. 1.2. Création de triggers dans la norme SQL (normalisation prévue dans SQL3) CREATE TRIGGER trigger_name AFTER | BEFORE INSERT | UPDATE | DELETE [ OR INSERT | UPDATE | DELETE …] ON relation_name WHEN condition Action-procedure [FOR EACH ROW | STATEMENT ] Exemple de création d’un trigger, sous Oracle, qui ajoute un tuple dans la table ‘commande_en_attente’, quand la quantité en stock d’un article devient inférieure à la quantité minimale spécifiée pour cet article : CREATE TRIGGER tg_reapprovision AFTER UPDATE ON article FOR EACH ROW WHEN article.qte_stock < article.qte_min DECLARE x number BEGIN SELECT count(*) INTO x FROM commande_en_attente C WHERE C.num_art = article.num_art ; IF (x = 0) THEN INSERT INTO commande_en_attente VALUES(article.num_art, article.qte_reapprov, SysDate); ENDIF; END; 1.3. Création de triggers dans Postgresql CREATE TRIGGER trigger_name AFTER | BEFORE INSERT | UPDATE | DELETE [ OR INSERT | UPDATE | DELETE …] ON relation_name [FOR EACH ROW | STATEMENT ] EXECUTE PROCEDURE function(); où trigger_name = nom du trigger ; relation_name = nom de la relation à laquelle s’applique l’événement function = fonction de trigger sous la forme d’une procédure stockée, exécutée quand survient l‘évènement 1/6 BASE DE DONNEES – 2d Cycle Note1 : PostgreSql ne permet pas l’exécution d’un trigger sur occurrence d’une condition mais uniquement AVANT ou APRES une commande (ou instruction = statement) de type Insert, Update ou Delete. Note2 : La fonction de trigger doit être créée avant le trigger. Elle doit être définie comme une fonction sans arguments retournant le type TRIGGER. Note3 : La fonction peut être exécutée pour chacun des tuples concernés par la commande (For each row) ou une seule fois pour la commande (For each statement). Pour l’instant PostgreSql n’implémente le trigger qu’au niveau tuple (For each row). Note4 : Pour l’instant, PostgreSql ne permet pas d’ouvrir et de fermer une transaction dans une procédure stockée. Les ordres BEGIN TRANSACTION et END TRANSACTION doivent être spécifiés avant et après l’appel de la procédure stockée. Un exemple de trigger sous PostgreSql : Dans le schéma relationnel d’une école de conduite, lors d’un changement de véhicule pour un élève, on souhaite conserver dans une table archive trace de ce véhicule et du véhicule qui le remplace. Eleve(numel, nomel, preel, adrel, cpel, fixel, mobel, immat#) Arch_eleve (numel, immat, datchange, immat_de_rempl) La fonction à créer pour le trigger est la suivante : CREATE FUNCTION archive_eleve () RETURNS TRIGGER AS ' BEGIN IF NEW.immat != OLD.immat THEN INSERT INTO arch_eleve Values (OLD.numel, OLD.immat,’today’,NEW.immat); END IF; RETURN NEW; END; ' LANGUAGE 'plpgsql'; Le trigger à créer est le suivant : CREATE TRIGGER trg_ach_elev BEFORE UPDATE ON eleve FOR EACH ROW EXECUTE PROCEDURE archive_eleve () ; 1.4. Exécution des triggers Le code de la procédure stockée du trigger est automatiquement exécuté par le SGBDR au moment et selon la condition spécifiés dans l'ordre de création du trigger : - avant la finalisation de l'opération si "BEFORE UPDATE|DELETE|INSERT" - après la finalisation de l'opération si "AFTER UPDATE|DELETE|INSERT" - avant la finalisation de l'opération si "BEFORE UPDATE|DELETE|INSERT" et sur occurrence de la condition spécifiée - après la finalisation de l'opération si "AFTER UPDATE|DELETE|INSERT" et sur occurrence de la condition spécifiée Exemple du trigger Oracle ci-dessus sachant que la quantité minimum requise pour l'article concerné est de 50, la commande suivante Update article set qte_stock = qte_stock + 100 where num_art = 12030; ne déclenchera pas l'exécution de la séquence de code du trigger alors que, avec un stock avant update de 100, la commande suivante Update article set qte_stock = qte_stock - 70 where num_art = 12030; déclenchera l'exécution de la séquence de code du trigger Exemple du trigger Postgresql ci-dessus les commandes suivantes 2/6 BASE DE DONNEES – 2d Cycle Insert into Eleve values(12030,'TARTAN','Pierre','5 rue des As','97110','0590000000','069000000','123WWW971'); Delete from Eleve where numel = 11111; ne déclencheront pas l'exécution de la fonction de trigger alors que, les commandes suivantes Update Eleve set cpel = '97139' where numel = 12030; Update Eleve set immat = '97ZZZ971' where numel = 12030; déclencheront l'exécution de la fonction de trigger 2. Langage procédural PL/SQL Le langage PL/SQL est un langage procédural comportant des instructions structurées (condition, boucles) en plus des instructions SQL. Disponible dans tous les SGBDR, il prend le nom de PL/pgSQL sous PostgreSql (PL/SQL sous Oracle). Un programme en PL/pgSQL est organisé en blocs de code créés dans la base par un ordre CREATE FUNCTION. Chaque bloc peut contenir une infinité de sous-blocs. Chaque sous-bloc doit respecter la structure de bloc , i.e. commencer par DECLARE (optionnel), suivi de BEGIN , et se terminer après les instructions par un END. CREATE FUNCTION identifier (arguments) RETURNS type AS ' DECLARE declaration; [...] BEGIN statement; [...] END; ' LANGUAGE 'plpgsql'; Commentaires PL/PGSQL Ligne simple de commentaires : -- ceci est un commentaire Bloc de commentaires : /* ceci est un bloc de commentaires */ Arguments des fonctions PL/pgSQL La liste d’arguments spécifie uniquement le type de chaque argument. Chaque argument est affecté d’un identifiant de la forme $i où i est le numéro de l’argument ($1 pour le 1er, $2 pour le second, …etc) Une variable peut être associé à un argument en utilisant ALIAS FOR dans la partie déclarative de la fonction : Identifiant_de_variable ALIAS FOR $i Variables PL/PGSQL Les variables doivent toutes être déclarées dans le sous-bloc DECLARE. nom_de variable [CONSTANT] type_de_donnée [NOT NULL] 3/6 [ [DEFAULT] := value ] ; BASE DE DONNEES – 2d Cycle Exemples : Paiement char := ‘’O’’; Nb_comm integer ; C_number CONSTANT integer := 100 ; Les variables non initialisées reçoivent la valeur NULL par défaut Les types simples sont les types standards SQL : boolean, text, char, varchar, time Ces types sont complétés par le type Record. integer, float, date, Variables PL/PGSQL prédéfinies FOUND : variable booléenne affectée par un ‘Select into’, peut être immédiatement testée après cette commande pour savoir si le select a retourné un résultat Variables PL/PGSQL prédéfinies spécifiques aux fonctions de TRIGGERS Nom Type Description Nouveau tuple créé après un ordre Insert ou Update NEW Record OLD Record Ancien tuple laissé par un ordre Delete ou Update Nom du trigger déclenché TG_NAME Name ‘BEFORE’ ou ‘AFTER’ selon la spécification du trigger TG_WHEN Text ‘ROW’ ou ‘STATEMENT’ selon la spécification du trigger TG_LEVEL Text ‘INSERT’ ou ‘UPDATE’ ou ‘DELETE’ selon l’opération qui a déclenché le TG_OP Text TG_RELID Oid TG_RELNAME Name trigger Identification (ID) de l’objet (relation) auquel est associé le trigger Nom de la relation à laquelle est associé le trigger Variables ‘attribut’ Une variable est déclarée avec ‘attribut’ quand elle destinée à contenir les valeurs d’un objet de la base ; il n’est pas nécessaire de connaître le type de cet objet, le type de la variable y sera automatiquement adapté. Les attributs sont au nombre de 2 : - attribut %TYPE. La déclaration est la suivante : nom_de_variable nom_de_table . nom_de_colonne%TYPE permet de définir une variable correspondant à un attribut d’une relation - attribut %ROWTYPE. La déclaration est la suivante : nom_de_variable nom_de_table%ROWTYPE permet de définir une variable correspondant à un tuple d’une relation Exemples : Un_client Client%ROWTYPE ; Nom_client Client.nomcl% TYPE; Instructions PL/PGSQL Affectation Variable := expression Où expression = constante | variable | expression arithmétique(variable, constante) | expression logique(variable, constante) Select into Variable Attribut from relation [ where …..] ; la variable reçoit la valeur de l’attribut projeté Select into V1, V2, ,Vn A1,A2, ,An from relation [ where …..] ; les variables V1,V2, ,Vn reçoivent les valeurs des attributs projetés A1,A2, ,An 4/6 BASE DE DONNEES – 2d Cycle NOTE : En PL/pgSQL, pour avoir l’équivalent de la commande SQL ‘Select into’ qui crée une nouvelle table, utiliser ‘Create table as select …‘ Return Return {variable | expression(variable, constante) } Instruction qui retourne une valeur du type spécifié dans la déclaration de la fonction Une instruction ‘Return’ doit toujours être incluse avant le ‘END’ de la fonction (même si elle n’est jamais exécutée) IF … THEN IF condition THEN instruction; [ .....] END IF; IF … THEN … ELSE IF condition THEN instruction; [ .....] ELSE instruction; [ .....] END IF; Imbrications de IF … THEN … ELSE Boucle inconditionnelle LOOP instruction [ .....] EXIT [étiquette] [WHEN condition ] END LOOP; Cette instruction boucle jusqu’à rencontrer l’instruction ‘EXIT’. Cette dernière peut être conditionnée par ‘WHEN’ qui précise quand la sortie de boucle doit s’effectuer. Boucle WHILE WHILE condition LOOP instruction [ .....] END LOOP; Similaire à la boucle ‘while’ dans les langages de programmation standard (Pascal, C,….) Boucle FOR FOR identifiant IN expression1 . . expression2 LOOP instruction [ .....] END LOOP; identifiant est une variable de type entier créée automatiquement en début de boucle puis détruite à la fin. Il n’est pas nécessaire de la déclarer explicitement (sous DECLARE). expression1 et expression2 sont des expressions entières. ou FOR variable IN instruction_SELECT LOOP instruction [ .....] END LOOP; variable est une variable déclarée de type RECORD ou avec l’attribut ROWTYPE Un exemple de fonction : Dans la base de données d’une école de conduite, on crée une fonction qui pour un numéro d’élève donné retourne une chaîne de caractère concaténant le nom et le prénom de l’élève modélisé par la relation : Eleve(numel, nomel, preel, adrel, cpel, fixel, mobel, immat#) La fonction est la suivante : CREATE FUNCTION ident_eleve (int4) RETURNS varchar(100) AS ' DECLARE Num_elev ALIAS FOR $1; Nom_elev eleve.nomel%TYPE; Pren_elev eleve.preel%TYPE; Ident varchar(100); BEGIN SELECT INTO Nom_elev, Pren_elev Nomel, preel FROM eleve WHERE numel = Num_elev; IF FOUND THEN Ident := Nom_elev || Pren_elev; 5/6 BASE DE DONNEES – 2d Cycle ELSE Ident := “Numero Eleve INEXISTANT” END IF; RETURN Ident; END; ' LANGUAGE 'plpgsql'; Utilisation de PL/PGSQL dans une base de données Définir le langage PL/pgSQL comme objet de la base de données Pour pouvoir être utilisé dans une base de données, le langage PL/PGSQL doit préalablement être défini par l’administrateur de la base comme un objet de la base de données. Deux méthodes pour cela : 1) sous ‘psql’, avec des ordres SQL : - d'abord créer dans la base le gestionnaire des appels procéduraux (procedural call Handler) Create Function plpgsql_call_handler () Returns OPAQUE As ‘/var/lib/pgsql/plpgsql.so’ Language ‘C’ ; où /var/lib/pgsql est le chemin du répertoire contenant la bibliothèque de PostgreSql ; dans certaines configuration il s’agit du répertoire /usr/ /lib/pgsql - ensuite créer l’objet language Create Language ‘plpgsql’ Handler plpgsql_call_handler Lancompiler ‘PL/Pgsql’ ; 2) sur la ligne de commande système, avec l’utilitaire : createlang plpgsql nom_base_de_données Créer une fonction stockée : Par la commande Create Function (Cf. ci-dessus) Appel d’une fonction stockée : Select nom_de_fonction (arguments) ; ou nom_de_variable := nom_de_fonction (arguments) ou PERFORM nom_de_fonction (arguments) 6/6