Créer des packages
Objectifs A la fin de ce chapitre, vous pourrez : décrire des packages et répertorier leurs éventuels composants créer un package regroupant des variables, constantes, exceptions, procédures, fonctions et curseurs associés désigner une structure de package comme publique ou privée appeler une structure de package décrire l'utilisation d'un package sans corps But du chapitre Dans ce chapitre, vous allez apprendre à créer les packages et à les utiliser avec leurs composants.
Présentation des packages Les packages : regroupent des types PL/SQL, des éléments et des sous-programmes présentant une relation logique sont constitués de deux éléments : spécification corps ne peuvent pas être appelés, paramétrés ou imbriqués permettent au serveur Oracle de lire simultanément plusieurs objets en mémoire Présentation des packages Les packages regroupent dans un conteneur les types PL/SQL, les éléments et les sous-programmes associés. Par exemple, un package Human Resources peut contenir des procédures d'embauche et de licenciement, des fonctions permettant l'octroi de commissions et de primes, ainsi que des variables relatives à l'exonération d'impôt. Un package est généralement constitué d'une spécification et d'un corps, qui sont stockés séparément dans la base de données. La spécification constitue l'interface avec les applications. Elle déclare les types, variables, constantes, exceptions, curseurs et sous-programmes disponibles. La spécification du package peut également inclure des pragmas (directives adressées au compilateur). Le corps définit entièrement les curseurs et les sous-programmes ; par conséquent, il implémente la spécification. Le package lui-même ne peut pas être appelé, paramétré ou imbriqué. Son format est cependant similaire à celui d'un sous-programme. Une fois écrit et compilé, le contenu peut être partagé par de nombreuses applications. Lorsque vous appelez une structure PL/SQL de package pour la première fois, l'ensemble du package est chargé en mémoire. Ainsi, les appels ultérieurs des structures contenues dans le même package ne requièrent pas d'opération d'entrée/sortie (E/S) disque.
Composants d'un package Variable publique Spécification du package Déclaration de la procédure A Procédure publique Variable privée Définition de la procédure B Procédure privée Corps du package Définition de la procédure A Procédure publique Développement d'un package La création d'un package s'effectue en deux étapes : vous devez créer au préalable la spécification, puis le corps du package. Les structures de package publiques sont déclarées dans les spécifications du package et sont définies dans le corps du package. Les structures de package privées sont définies uniquement dans le corps du package. Remarque : La spécification et le corps du package sont stockés séparément dans la base de données par le serveur Oracle. Vous pouvez ainsi modifier la définition d'une structure de programme dans le corps du package, sans que le serveur Oracle invalide d'autres objets de schéma appelant ou référençant la structure de programme. Variable locale
Référencer des objets de package Spécification du package Déclaration de la procédure A Définition de la procédure B Corps du package Définition de la procédure A Développement d'un package (suite)
Chargement et exécution du fichier file.sql Développer un package Editeur Code iSQL*Plus 1 Chargement et exécution du fichier file.sql 2 Code source Oracle Compilation Pseudo- code Méthode de développement d'un package 1. Rédigez la syntaxe : entrez le code correspondant dans un éditeur de texte, puis enregistrez-le en tant que fichier script SQL. 2. Compilez le code : exécutez le fichier script SQL pour générer et compiler le code source. Le code source est compilé en pseudo-code. Exécution
Développer un package L'enregistrement du texte de l'instruction CREATE PACKAGE dans deux fichiers SQL distincts facilite les modifications ultérieures du package Une spécification de package peut exister sans corps de package, mais l'inverse n'est pas vrai Méthode de développement d'un package Le développement d'un package se décompose en trois étapes de base, similaires à celles du développement d'une procédure autonome. 1. Rédigez le texte de l'instruction CREATE PACKAGE dans un fichier script SQL pour créer la spécification du package et exécuter le fichier script. Le code source est compilé en pseudo-code et stocké dans le dictionnaire de données. 2. Rédigez le texte de l'instruction CREATE PACKAGE BODY dans un fichier script SQL pour créer la spécification du package et exécuter le fichier script. Le code source est compilé en pseudo-code et stocké dans le dictionnaire de données. 3. Appelez une structure publique du package depuis un environnement de serveur Oracle.
Créer la spécification du package Syntaxe: CREATE [OR REPLACE] PACKAGE package_name IS|AS public type and item declarations subprogram specifications END package_name; L'option REPLACE supprime et recrée la spécification du package Par défaut, la valeur NULL est affectée aux variables déclarées dans la spécification du package Toutes les structures déclarées dans une spécification de package peuvent être visibles par les utilisateurs disposant de privilèges sur le package Création d'une spécification de package Pour créer des packages, vous devez déclarer toutes les structures publiques dans la spécification du package. Indiquez l'option REPLACE lorsque la spécification du package existe déjà. Si nécessaire, initialisez une variable en lui affectant une valeur constante ou une formule dans la déclaration ; sinon, la valeur NULL est implicitement affectée à la variable. Définition syntaxique
Déclarer des structures publiques Package COMM_PACKAGE G_COMM 1 Spécification du package Déclaration de la procédure RESET_COMM 2 Exemple de spécification de package Dans la diapositive, G_COMM est une variable publique (globale) et RESET_COMM, une procédure publique. Dans la spécification du package, vous déclarez les variables, procédures et fonctions publiques. Les procédures ou fonctions publiques sont des sous-programmes qui peuvent être appelés plusieurs fois par d'autres structures du même package ou extérieures au package.
Exemple de création de spécification de package CREATE OR REPLACE PACKAGE comm_package IS g_comm NUMBER := 0.10; --initialized to 0.10 PROCEDURE reset_comm (p_comm IN NUMBER); END comm_package; / G_COMM est une variable globale dont la valeur d'initialisation est 0,10. RESET_COMM est une procédure publique implémentée dans le corps du package. Spécification de package pour COMM_PACKAGE Dans la diapositive, la variable G_COMM et la procédure RESET_COMM sont des structures publiques.
Créer le corps du package Syntaxe: CREATE [OR REPLACE] PACKAGE BODY package_name IS|AS private type and item declarations subprogram bodies END package_name; L'option REPLACE supprime et recrée le corps du package Les identificateurs définis exclusivement dans le corps du package sont des structures privées. Ils ne sont pas visibles à l'extérieur du corps du package Toutes les structures privées doivent être déclarées avant d'être utilisées dans les structures publiques Créer le corps du package Pour créer un package, définissez toutes les structures publiques et privées dans le corps du package. Indiquez l'option REPLACE lorsque le corps du package existe déjà. L'ordre de définition des sous-programmes dans le corps du package est important : vous devez déclarer une variable pour qu'une autre variable ou un autre programme puisse y faire référence ; en outre, vous devez déclarer ou définir des sous-programmes privés avant de les appeler depuis d'autres sous-programmes. En règle générale, les variables et les sous-programmes privés sont définis avant les sous-programmes publics dans le corps du package. Définition syntaxique Définissez toutes les procédures et fonctions, publiques et privées, dans le corps du package.
Structures publiques et privées Package COMM_PACKAGE G_COMM 1 Spécification du package Déclaration de la procédure RESET_COMM 2 Définition de la fonction VALIDATE_COMM 3 Corps du package Exemple de création de corps de package Sur la diapositive présentée : 1 est une variable publique (globale), 2 est une procédure publique, 3 est une fonction privée. Vous pouvez définir une procédure ou une fonction privée, pour organiser de façon modulaire le code des procédures et des fonctions publiques, et le clarifier. Remarque : La fonction privée est présentée dans la diapositive au-dessus de la procédure publique. Lorsque vous codez le corps du package, la définition de la fonction privée doit se trouver au-dessus de la définition de la procédure publique. Seules les déclarations de sous-programme et de curseur sans corps dans une spécification de package présentent une implémentation sous-jacente dans le corps du package. Par conséquent, si une spécification ne déclare que des types, des constantes, des variables, des exceptions et des spécifications d'appel, le corps du package n'est pas nécessaire. Il peut cependant être utilisé pour l'initialisation d'éléments déclarés dans la spécification du package. Définition de la procédure RESET_COMM 2
Exemple de création de corps de package comm_pack.sql CREATE OR REPLACE PACKAGE BODY comm_package IS FUNCTION validate_comm (p_comm IN NUMBER) RETURN BOOLEAN v_max_comm NUMBER; BEGIN SELECT MAX(commission_pct) INTO v_max_comm FROM employees; IF p_comm > v_max_comm THEN RETURN(FALSE); ELSE RETURN(TRUE); END IF; END validate_comm; ... Corps du package COMM_PACKAGE Définissez une fonction pour valider la commission. Son montant ne doit pas dépasser celui de la commission la plus élevée parmi tous les employés.
Exemple de création de corps de package comm_pack.sql PROCEDURE reset_comm (p_comm IN NUMBER) IS BEGIN IF validate_comm(p_comm) THEN g_comm:=p_comm; --reset global variable ELSE RAISE_APPLICATION_ERROR(-20210,'Invalid commission'); END IF; END reset_comm; END comm_package; / Corps du package COMM_PACKAGE (suite) Définissez une procédure vous permettant de réinitialiser et de valider la commission en cours.
Appeler des structures de package Exemple 1: Appeler une fonction depuis une procédure du même package. CREATE OR REPLACE PACKAGE BODY comm_package IS . . . PROCEDURE reset_comm (p_comm IN NUMBER) IS BEGIN IF validate_comm(p_comm) THEN g_comm := p_comm; ELSE RAISE_APPLICATION_ERROR (-20210, 'Invalid commission'); END IF; END reset_comm; END comm_package; Appeler des structures de package Une fois le package stocké dans la base de données, vous pouvez appeler une structure de package depuis l'intérieur ou l'extérieur du package, selon le statut privé ou public de la structure. Lorsque vous appelez une procédure ou une fonction de package depuis le même package, il n'est pas nécessaire de qualifier son nom. Exemple 1 Appelez la fonction VALIDATE_COMM depuis la procédure RESET_COMM. Les deux sous-programmes résident dans le package COMM_PACKAGE.
Appeler des structures de package Exemple 2: Appeler une procédure de package depuis iSQL*Plus. Exemple 3: Appeler une procédure de package dans un autre schéma. Exemple 4: Appeler une procédure de package dans une base de données distante. EXECUTE comm_package.reset_comm(0.15) EXECUTE scott.comm_package.reset_comm(0.15) Appeler des structures de package (suite) Lorsque vous appelez une procédure ou une fonction de package depuis l'extérieur du package, vous devez qualifier son nom avec le nom du package. Exemple 2 Appelez la procédure RESET_COMM depuis iSQL*Plus, en affectant la valeur 0,15 à la commission en cours pour la session utilisateur. Exemple 3 Appelez la procédure RESET_COMM située dans le schéma SCOTT depuis iSQL*Plus, en affectant la valeur 0,15 à la commission en cours pour la session utilisateur. Exemple 4 Appelez depuis iSQL*Plus la procédure RESET_COMM stockée dans une base de données distante déterminée par le nom du lien de base de données NY, et affectez la valeur 0,15 à la commission en cours pour la session utilisateur. Respectez les conventions d'appellation standard pour appeler une procédure dans un autre schéma ou dans une autre base de données située sur un nœud différent. EXECUTE comm_package.reset_comm@ny(0.15)
Déclarer un package sans corps CREATE OR REPLACE PACKAGE global_consts IS mile_2_kilo CONSTANT NUMBER := 1.6093; kilo_2_mile CONSTANT NUMBER := 0.6214; yard_2_meter CONSTANT NUMBER := 0.9144; meter_2_yard CONSTANT NUMBER := 1.0936; END global_consts; / EXECUTE DBMS_OUTPUT.PUT_LINE('20 miles = '||20* global_consts.mile_2_kilo||' km') Déclarer un package sans corps Vous pouvez déclarer des variables publiques (globales) pour la durée de la session utilisateur. Vous pouvez créer une spécification de package qui ne requiert pas de corps de package. Comme indiqué précédemment dans le chapitre, le corps du package n'est pas nécessaire si une spécification ne déclare que des types, des constantes, des variables, des exceptions et des spécifications d'appel. Exemple Dans l'exemple de la diapositive, une spécification de package contenant plusieurs taux de conversion est créée. Tous les identificateurs globaux sont déclarés en tant que constantes. La prise en charge de la spécification de package ne nécessite pas de corps de package, car les détails de l'implémentation ne sont pas requis pour les structures de la spécification du package.
Référencer une variable publique depuis une procédure autonome Exemple: CREATE OR REPLACE PROCEDURE meter_to_yard (p_meter IN NUMBER, p_yard OUT NUMBER) IS BEGIN p_yard := p_meter * global_consts.meter_2_yard; END meter_to_yard; / VARIABLE yard NUMBER EXECUTE meter_to_yard (1, :yard) PRINT yard Exemple Utilisez la procédure METER_TO_YARD pour convertir des mètres en yards, en utilisant le taux de conversion contenu dans GLOBAL_CONSTS. Lorsque vous faites référence à une variable, un curseur, une constante ou une exception depuis l'extérieur du package, vous devez qualifier son nom avec le nom du package.
Supprimer des packages Utilisez la syntaxe suivante pour supprimer la spécification et le corps du package : Utilisez la syntaxe suivante pour supprimer le corps du package : DROP PACKAGE package_name; DROP PACKAGE BODY package_name; Supprimer un package Lorsqu'un package n'est plus nécessaire, vous pouvez le supprimer en utilisant une instruction SQL dans iSQL*Plus. Un package est constitué de deux parties ; vous avez donc la possibilité de supprimer l'ensemble du package ou de ne supprimer que son corps et d'en conserver la spécification.
Règles relatives au développement des packages Créer des structures de package pour une utilisation générale Définir la spécification avant le corps du package La spécification du package doit contenir uniquement les structures à rendre publiques Placer les éléments dans la partie déclarative du corps du package, lorsqu'ils doivent être tenus à jour tout au long d'une session ou durant plusieurs transactions En cas de modification de la spécification du package, chaque sous-programme y faisant référence doit être compilé La spécification du package doit contenir le moins de structures possible Règles relatives à l'écriture de packages Les packages doivent être aussi généraux que possible pour pouvoir être réutilisés dans des applications ultérieures. Par conséquent, évitez d'écrire des packages contenant des doublons de fonctions offertes par le serveur Oracle. Les spécifications des packages reflètent la conception d'une application, c'est pourquoi elles doivent être définies avant les corps des packages. Par ailleurs, elles ne doivent contenir que les structures auxquelles les utilisateurs des packages auront accès. Ainsi, les autres développeurs ne pourront pas détourner l'utilisation du package en basant le code sur des détails inappropriés. Placez les éléments dans la partie déclarative du corps du package lorsque vous devez les tenir à jour tout au long d'une session ou durant plusieurs transactions. Par exemple, déclarez une variable nommée NUMBER_EMPLOYED en tant que variable privée si tous les appels de procédure utilisant la variable doivent être tenus à jour. Lorsque la variable est déclarée en tant que variable globale dans la spécification du package, sa valeur est initialisée lors d'une session, au premier appel d'une structure du package. Toute modification du corps du package requiert la recompilation des structures dépendantes, tandis que les modifications de la spécification du package requièrent la recompilation de tous les sous-programmes stockés faisant référence au package. Pour limiter le nombre de recompilations lors des changements de code, placez le moins de structures possible dans la spécification du package.
Avantages liés aux packages Modularité : encapsule les structures associées Conception simplifiée des applications : la spécification et le corps sont codés et compilés séparément Masquage d'informations : seules les déclarations contenues dans la spécification du package sont visibles et accessibles aux applications Les structures privées du corps du package sont masquées et inaccessibles L'ensemble du code est masqué dans le corps du package Avantages liés à l'utilisation de packages Les packages constituent une alternative à la création de procédures et de fonctions en tant qu'objets de schéma autonomes ; en outre, ils offrent divers avantages. Modularité Vous encapsulez dans un module nommé des structures de programmation présentant des relations logiques. Chaque package est facile à comprendre ; de plus, l'interface entre les packages est simple, claire et bien définie. Conception simplifiée des applications Au départ, vous n'avez besoin que des informations d'interface contenues dans la spécification du package. Vous pouvez coder et compiler une spécification sans son corps. Par la suite, vous pouvez également compiler les sous-programmes stockés faisant référence au package. Il n'est pas nécessaire de définir le corps du package dans son intégralité tant que vous n'êtes pas prêt à exécuter l'application. Masquage d'informations Vous pouvez déterminer quelles structures sont publiques (visibles et accessibles) ou privées (masquées et inaccessibles). Seules les déclarations qui se trouvent dans la spécification du package sont visibles et accessibles aux applications. Le corps du package masque la définition des structures privées de sorte que toute modification de la définition affecte uniquement le package (et non l'application ou les programmes appelants). Vous pouvez ainsi modifier l'implémentation sans recompiler les programmes appelants. En outre, vous garantissez l'intégrité du package en masquant les détails de l'implémentation aux utilisateurs.
Avantages liés aux packages Fonctionnalité ajoutée : persistance des variables et des curseurs Performances accrues : l'ensemble du package est chargé en mémoire la première fois que celui-ci est référencé une seule copie est chargée en mémoire pour l'ensemble des utilisateurs la hiérarchie des dépendances est simplifiée Surcharge : plusieurs sous-programmes portant le même nom Avantages liés à l'utilisation de packages (suite) Fonctionnalité ajoutée Les variables et curseurs publics de package durent le temps d'une session. Par conséquent, ils peuvent être partagés par tous les sous-programmes s'exécutant dans l'environnement. Ils permettent également de gérer les données de plusieurs transactions sans les stocker dans la base de données. Les structures privées durent également le temps de la session, mais elles sont accessibles uniquement depuis le package. Performances accrues Lorsque vous appelez un sous-programme de package pour la première fois, l'ensemble du package est chargé en mémoire. Ainsi, les appels ultérieurs de sous-programmes associés au sein du même package ne requièrent pas d'opérations supplémentaires d'E/S disque. Les sous-programmes de package mettent également fin aux dépendances en cascade et évitent les compilations inutiles. Surcharge Les packages vous permettent de surcharger les procédures et les fonctions ; en d'autres termes, vous pouvez créer au sein du même package plusieurs sous-programmes portant le même nom, mais dont les valeurs ou les types de données des paramètres sont différents.
Synthèse Ce chapitre vous a permis d'apprendre à : optimiser l'organisation, la gestion, la sécurité et les performances en utilisant des packages regrouper les procédures et les fonctions associées au sein d'un package modifier un corps de package sans affecter sa spécification définir un accès sécurisé à l'ensemble du package Synthèse Vous pouvez regrouper les procédures et les fonctions associées au sein d'un package. Les packages permettent d'optimiser l'organisation, la gestion, la sécurité et les performances. Un package est constitué d'une spécification et d'un corps. Vous pouvez modifier un corps de package sans affecter sa spécification.
Synthèse Ce chapitre vous a permis d'apprendre à : masquer le code source aux utilisateurs charger l'ensemble du package en mémoire au premier appel réduire les accès au disque pour les appels ultérieurs fournir les identificateurs de la session utilisateur Synthèse (suite) Les packages permettent de masquer le code source aux utilisateurs. Lorsque vous appelez un package pour la première fois, il est intégralement chargé en mémoire, ce qui réduit les accès au disque pour les appels ultérieurs.
Synthèse Commande Tâche CREATE [OR REPLACE] PACKAGE CREATE [OR REPLACE] PACKAGE BODY DROP PACKAGE DROP PACKAGE BODY Tâche Créer (ou modifier) une spécification de package existante Créer (ou modifier) un corps de package existant Supprimer la spécification et le corps du package Supprimer le corps du package uniquement Synthèse (suite) Vous pouvez créer, supprimer et modifier des packages. La commande DROP PACKAGE vous permet de supprimer la spécification et le corps du package. Vous pouvez supprimer le corps du package sans affecter sa spécification.
Présentation de l'exercice 5 Dans cet exercice, vous allez : créer des packages appeler des programmes de package Présentation de l'exercice 5 Dans cet exercice, vous allez créer des spécifications et des corps de package. Vous allez également appeler les structures des packages, en utilisant des exemples de données.
Assurez-vous que le composant heure dans la date est ignoré. Exercice 5 1. Créez la spécification et le corps du package JOB_PACK. (Vous pouvez enregistrer le corps et la spécification du package dans deux fichiers distincts.) Le package contient les procédures ADD_JOB, UPD_JOB et DEL_JOB, ainsi que la fonction Q_JOB. Remarque : Utilisez le code des fichiers script précédemment enregistrés lors de la création du package. a. Rendez toutes les structures publiques. Remarque : Evaluez la nécessité de conserver les fonctions et des procédures autonomes que vous avez mises en package. b. Appelez la procédure ADD_JOB en transmettant les valeurs IT_SYSAN et SYSTEMS ANALYST en tant que paramètres. c. Interrogez la table JOBS pour consulter les résultats. 2. Créez et appelez un package contenant des structures privées et publiques. a. Créez la spécification et le corps du package EMP_PACK, contenant la procédure NEW_EMP en tant que structure publique et la fonction VALID_DEPTID en tant que structure privée. (Vous pouvez enregistrer la spécification et le corps du package dans des fichiers distincts.) b. Appelez la procédure NEW_EMP, en utilisant la valeur 15 comme numéro de service. Etant donné que le numéro de service 15 n'existe pas dans la table DEPARTMENTS, vous devez obtenir un message d'erreur comme indiqué dans le gestionnaire d'exceptions de la procédure. c. Appelez la procédure NEW_EMP en utilisant le numéro de service existant 80. Si vous avez le temps : 3. a. Créez un package nommé CHK_PACK contenant les procédures CHK_HIREDATE et CHK_DEPT_MGR. Rendez les deux structures publiques (vous pouvez enregistrer la spécification et le corps du package dans des fichiers distincts). La procédure CHK_HIREDATE vérifie si la date d'embauche d'un employé correspond à la plage suivante : [SYSDATE – 50 ans, SYSDATE + 3 mois] Remarque : Si la date n'est pas valide, déclenchez une erreur d'application avec un message approprié indiquant la raison pour laquelle la date indiquée ne peut être acceptée. Assurez-vous que le composant heure dans la date est ignoré. Utilisez une constante pour indiquer la limite de 50 ans. Une valeur NULL obtenue pour la date d'embauche doit être traitée comme une date d'embauche non valide. La procédure CHK_DEPT_MGR vérifie la combinaison service/responsable pour un employé donné. Elle accepte un ID d'employé et un numéro de responsable. Elle vérifie si l'employé et le responsable travaillent dans le même service. Elle vérifie également si l'intitulé du poste correspondant au numéro de responsable indiqué est MANAGER. Remarque : Si la combinaison numéro de service/responsable n'est pas valide, vous devez déclencher une erreur d'application avec un message approprié.
Exercice 5 (suite) b. Testez la procédure CHK_HIREDATE en exécutant la commande suivante : EXECUTE chk_pack.chk_hiredate('01-JAN-47') Que se passe-t-il et pourquoi ? c. Testez la procédure CHK_HIREDATE en exécutant la commande suivante : EXECUTE chk_pack.chk_hiredate(NULL) d. Testez la procédure CHK_DEPT_MGR en exécutant la commande suivante : EXECUTE chk_pack.chk_dept_mgr(117,100)