LOG660 - Bases de données de haute performance Interface de programmation Application / BD Hiver 2011 C. Desrosiers Département de génie logiciel et des TI
Interface entre SQL et un programme SQL incomplet Défaut d'impédance (impedance mismatch) modèle de données BD modèle de données du langage de programmation Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 2
Interface programmatique (Call-Level Interface - SQL/CLI) API spécifique au SGBD e.g. Oracle Call Interface (OCI) non portable API normalisée standard de facto ODBC développé par Microsoft pour le C pilote ODBC pour client/serveur SQL/CLI de SQL:1999 inspirée de ODBC JDBC pour Java Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 3
SQL enchâssé (Embedded SQL) Code SQL dans le source du langage hôte Syntaxe spéciale Pré-compilation Oracle : pro*c/c ++, pro*cobol,, SQLJ Moins portable pré-compilateur spécifique au SGBD traduit en API du SGBD SQLJ (partie 0) traduit en API standard JDBC Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 4
Extension procédurale à SQL (Persistent Stored Modules - SQL/PSM) SQL + structures de contrôle procédures, fonctions, packages support direct des types SQL pour les variables exécution au niveau serveur de BD Oracle PL/SQL Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 5
Bloc PL/SQL [DECLARE déclaration [déclaration]...] BEGIN séquenceenoncés [EXCEPTION exception_énoncé [exception_énoncé]...] END Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 6
Exécution d un bloc sous SQL*plus SQL> DECLARE 2 laquantitéenstock Article.quantitéEnStock%TYPE; 3 BEGIN 4 SELECT quantitéenstock INTO laquantitéenstock 5 FROM Article 6 WHERE noarticle = 10; 7 IF laquantitéenstock = 0 THEN 8 DBMS_OUTPUT.PUT_LINE('L article est en rupture de stock'); 9 ELSE 10 DBMS_OUTPUT.PUT('Quantité en stock :'); 11 DBMS_OUTPUT.PUT_LINE(laQuantitéEnStock); 12 END IF; 13 EXCEPTION 14 WHEN NO_DATA_FOUND THEN 15 DBMS_OUTPUT.PUT_LINE('Numéro d article inexistant'); 16 WHEN OTHERS THEN 17 RAISE_APPLICATION_ERROR(-20001,'Erreur soulevée par le SELECT'); 18 END; 19 / Quantité en stock :20 PL/SQL procedure successfully completed. Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 7
Déclaration de variables PL/SQL (DECLARE) lenoclient lenoclient Client.noClient%TYPE; INTEGER; Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 8
Transfert d'une valeur de colonne d'un SELECT dans une variable (clause INTO) SELECT INTO FROM WHERE noclient, datecommande lenoclient, ladatecommande Commande nocommande = lenocommande; Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 9
Affectation en PL/SQL laquantitéenattente:= laquantitécommandée -laquantitélivrée; Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 10
Structure de contrôle IF IF (laquantitélivrée IS NULL) THEN DBMS_OUTPUT.PUT_LINE(' livraison en attente'); ELSE laquantitéenattente:= laquantitécommandée -laquantitélivrée; IF (laquantitéenattente = 0) THEN DBMS_OUTPUT.PUT_LINE(' livraison complétée'); ELSE DBMS_OUTPUT.PUT (' quantité en attente :'); DBMS_OUTPUT.PUT_LINE(laQuantitéEnAttente); END IF ; END IF ; Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 11
Boucles (LOOP, FOR, WHILE) LOOP séquenceenoncés END LOOP ; FOR indice IN [REVERSE] valeurinitiale..valeurfinale LOOP séquenceenoncés END LOOP ; WHILE condition LOOP séquenceenoncés END LOOP ; Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 12
Traitement d'exception (EXCEPTION, RAISE) Déclarer Soulever Attraper nomexception RAISE nomexception WHEN nomexception THEN séquenceénoncés EXCEPTION; Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 13
Curseur PL/SQL (CURSOR) CURSOR lignescommande(unnocommande Commande.noCommande%TYPE)IS SELECT noarticle, quantité FROM LigneCommande WHERE LigneCommande.noCommande = unnocommande ; OPEN lignescommande(lenocommande); -- Le OPEN ouvre le CURSOR en lui passant les paramètres LOOP FETCH lignescommande INTO lenoarticle, laquantitécommandée; -- Le FETCH retourne la ligne suivante EXIT WHEN lignescommande%notfound; -- %NOTFOUND est un attribut du CURSOR qui permet de déterminer -- si le FETCH a atteint la fin de la table END LOOP; -- Le CLOSE ferme le CURSOR CLOSE lignescommande; Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 14
Boucle FOR pour curseur PL/SQL FOR uneligne IN lignescommande(lenocommande) LOOP DBMS_OUTPUT.PUT('noArticle :'); DBMS_OUTPUT.PUT(uneLigne.noArticle); DBMS_OUTPUT.PUT(' quantité commandée:'); DBMS_OUTPUT.PUT(uneLigne.quantité); -- Chercher la quantité déjà livrée SELECT SUM(quantitéLivrée) INTO laquantitélivrée FROM DétailLivraison WHERE noarticle = uneligne.noarticle AND nocommande = lenocommande ; IF (laquantitélivrée IS NULL) THEN DBMS_OUTPUT.PUT_LINE(' livraison en attente'); ELSE laquantitéenattente:= uneligne.quantité -laquantitélivrée; IF (laquantitéenattente = 0) THEN DBMS_OUTPUT.PUT_LINE(' livraison complétée'); ELSE DBMS_OUTPUT.PUT (' quantité en attente :'); DBMS_OUTPUT.PUT_LINE(laQuantitéEnAttente); END IF ; END IF ; END LOOP; Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 15
Procédures et fonctions PL/SQL stockées SQL> CREATE FUNCTION fquantitéenstock 2 (unnoarticle Article.noArticle%TYPE) 3 RETURN Article.quantitéEnStock%TYPE IS 4 5 unequantitéenstock Article.quantitéEnStock%TYPE; 6 BEGIN 7 SELECT quantitéenstock 8 INTO unequantitéenstock 9 FROM Article 10 WHERE noarticle = unnoarticle; 11 RETURN unequantitéenstock; 12 END fquantitéenstock; 13 14 / Function created. SQL> select fquantitéenstock(10) from dual; FQUANTITÉENSTOCK(10) -------------------- 10 Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 16
Procédure stockée SQL> CREATE PROCEDURE pmodifierquantitéenstock 2 (unnoarticle Article.noArticle%TYPE, 3 nouvellequantitéenstock Article.quantitéEnStock%TYPE) IS 4 BEGIN 5 UPDATE Article 6 SET quantitéenstock = nouvellequantitéenstock 7 WHERE noarticle = unnoarticle; 8 END pmodifierquantitéenstock; 9 / Procedure created. SQL> EXECUTE pmodifierquantitéenstock(10,20); PL/SQL procedure successfully completed. SQL> SELECT * FROM Article WHERE noarticle = 10; NOARTICLE DESCRIPTION PRIXUNITAIRE QUANTITÉENSTOCK ---------- -------------------- ------------ --------------- 10 Cèdre en boule 10,99 20 Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 17
Privilèges dans une routine stockée Privilèges de l'appelant (invoker rights) CREATE PROCEDURE pmodifierquantitéenstock (unnoarticle Article.noArticle%TYPE, nouvellequantitéenstock Article.quantitéEnStock%TYPE) AUTHID CURRENT_USER IS BEGIN UPDATE Article SET quantitéenstock = nouvellequantitéenstock WHERE noarticle = unnoarticle; END pmodifierquantitéenstock; Privilèges de la routine (definer rights) privilèges du créateur par défaut Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 18
Exemple privilège de l appelant SQL> connect godin/oracle Connected. SQL> CREATE OR REPLACE PROCEDURE pmodifierquantitéenstock 2 (unnoarticle Article.noArticle%TYPE, 3 nouvellequantitéenstock Article.quantitéEnStock%TYPE) 4 AUTHID CURRENT_USER IS 5 BEGIN 6 UPDATE Article 7 SET quantitéenstock = nouvellequantitéenstock 8 WHERE noarticle = unnoarticle; 9 END pmodifierquantitéenstock; 10 / Procedure created. SQL> grant execute on pmodifierquantitéenstock to public; Grant succeeded. SQL> connect test/oracle Connected. SQL> EXECUTE godin.pmodifierquantitéenstock (10,500); PL/SQL procedure successfully completed. SQL> select * from article; NOARTICLE DESCRIPTION PRIXUNITAIRE QUANTITÉENSTOCK ---------- -------------------- ------------ --------------- 10 Cèdre en boule 10,99 500 20 Sapin 12,99 10 SQL> select * from godin.article; select * from godin.article * ERROR at line 1: ORA-00942: table or view does not exist Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 19
Exemple privilège du créateur SQL> connect godin/oracle Connected. SQL> CREATE OR REPLACE PROCEDURE pmodifierquantitéenstock 2 (unnoarticle Article.noArticle%TYPE, 3 nouvellequantitéenstock Article.quantitéEnStock%TYPE) 4 IS 5 BEGIN 6 UPDATE Article 7 SET quantitéenstock = nouvellequantitéenstock 8 WHERE noarticle = unnoarticle; 9 END pmodifierquantitéenstock; 10 / Procedure created. SQL> grant execute on pmodifierquantitéenstock to public; Grant succeeded. SQL> connect test/oracle Connected. SQL> EXECUTE godin.pmodifierquantitéenstock (10,700); PL/SQL procedure successfully completed. SQL> select * from article; NOARTICLE DESCRIPTION PRIXUNITAIRE QUANTITÉENSTOCK ---------- -------------------- ------------ --------------- 10 Cèdre en boule 10,99 500 20 Sapin 12,99 10 Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 20
Exemple privilège du créateur (suite) SQL> select * from godin.article; select * from godin.article * ERROR at line 1: ORA-00942: table or view does not exist SQL> connect godin/oracle Connected. SQL> select * from article; NOARTICLE DESCRIPTION PRIXUNITAIRE QUANTITÉENSTOCK ---------- -------------------- ------------ --------------- 10 Cèdre en boule 10,99 700 20 Sapin 12,99 10 40 Épinette bleue 25,99 10 50 Chêne 60 Érable argenté 22,99 15,99 10 10 70 Herbe à puce 80 Poirier 10,99 26,99 10 10 81 Catalpa 90 Pommier 25,99 25,99 10 10 95 Génévrier 15,99 10 10 rows selected. Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 21
Package PL/SQL CREATE PACKAGE nompaquetage AS listedessignaturesdesfonctions&procédures END nompaquetage ; CREATE PACKAGE BODY nompaquetage AS délaration [déclaration] BEGIN séquenceénoncésinitialisation END nompaquetage; nompaquetage.nomobjet Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 22
JDBC API standard pour JAVA http://java.sun.com/products/jdbc/ Ensemble de classes Besoin d installer un pilote JDBC dans l environnement JAVA Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 23
Architecture pour les pilotes JDBC Application Java (import java.sql.*) API JDBC Type 1 Passerelle JDBC- ODBC Pilote ODBC (e.g. pilote ODBC Oracle) Type 2 Partie Java API client du SGBD (e.g. ocijdbc8.dll pour Oracle) Type 3 Pilote JDBC générique Type 4 Pilote JDBC tout Java (e.g. Oracle thin) Type? Oracle serverside thin et internal driver Serveur JDBC Serveur de BD Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 24
Chargement d'un pilote JDBC et établissement d'une connexion Charger les pilotes JDBC d Oracle Class.forName ("oracle.jdbc.driver.oracledriver"); Établir une connexion avec le pilote OCI8 pour un serveur Oracle local Connection uneconnection = DriverManager.getConnection ("jdbc:oracle:oci8:@", "toto", "secret"); Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 25
Création d un énoncé SQL (Statement) Statement unenoncésql = uneconnection.createstatement (); <<Interface>> Statement executequery(arg0 : S tring) : ResultSet executeupdate(arg0 : St ring) : int close() : void getmaxfieldsize() : int setmaxfieldsize(arg0 : int) : void getmaxrows() : int setmaxrows(arg0 : int) : void setescapeprocessing(arg0 : boolean) : void getquerytimeout() : int setquerytimeout(arg0 : int) : void cancel() : void getw arnings() : SQLWarning clearwarnings() : void setcursorname(arg0 : String) : void execute(arg0 : String) : boolean getresultset() : ResultSet getupdatecount() : int getmoreresults() : boolean setfetchdirection(arg0 : int) : void getfet chdirection() : int setfetchsize(arg0 : int) : void getfetchsize() : int getresultsetconcurrency() : int getresultsettype() : int addbatch(arg0 : String) : void clearbatch() : void executebatch() : int[] getconnection() : Connection Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 26
Exécution d'une opération de mise à jour (INSERT, DELETE, UPDATE) import java.sql.*; class ClientInsertJDBC { public static void main (String args []) throws SQLException, ClassNotFoundException, java.io.ioexception { // Charger le pilote JDBC d'oracle Class.forName ("oracle.jdbc.driver.oracledriver"); // Connexion à une BD Connection uneconnection = DriverManager.getConnection ("jdbc:oracle:oci8:@", "godin", "oracle"); // Création d'un énoncé associé à la Connection Statement unenoncésql = uneconnection.createstatement (); // Insertion d'une ligne dans la table Client int n = unenoncésql.executeupdate ("INSERT INTO CLIENT " + "VALUES (100, 'G. Lemoyne-Allaire', '911')"); System.out.println ("Nombre de lignes inserees:" + n); } } // Fermeture de l'énoncé et de la connexion unenoncésql.close(); uneconnection.close(); Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 27
Exécution d'un SELECT (ResultSet) Début analogue à l'exemple précédent // Création d'un énoncé associé à la Connexion Statement unenoncésql = uneconnection.createstatement(); // Exécution d'un SELECT ResultSet résultatselect = unenoncésql.executequery ("SELECT noclient, nomclient "+ "FROM CLIENT " + "WHERE noclient > 40"); // Itérer sur les lignes du résultat du SELECT et extraire les valeurs // des colonnes dans des variables JAVA } } while (résultatselect.next ()){ int noclient = résultatselect.getint ("noclient"); String nomclient = résultatselect.getstring ("nomclient"); System.out.println ("Numéro du client:" + noclient); System.out.println ("Nom du client:" + nomclient); } Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 28
Support des types SQL:1999 sous JDBC 2 CREATE TABLE tableblob ( idblob INTEGER PRIMARY KEY, imageblob) // Chercher le BLOB locator ResultSet unresultset = unenoncésql.executequery ("SELECT * FROM tableblob WHERE idblob = 1"); if (unresultset.next()){ int idblob = unresultset.getint(1); Blob unblob = unresultset.getblob(2); // Chercher la taille du BLOB et l'afficher int taille = (int)unblob.length(); System.out.println("Taille du BLOB" + taille); // Lire le BLOB dans un tableau d'octets byte octets[] = unblob.getbytes(1, taille); // Créer un fichier contenant les octets lus FileOutputStream unfichier = new FileOutputStream("C:/forte4j/Development/ExemplesJDBC/CopieCoq1.gif"); unfichier.write(octets); unfichier.close(); Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 29
Compilation et exécutions multiples avec la classe PreparedStatement Compilation + exécution combinée au executequery Statement unenoncésql = uneconnection.createstatement(); ResultSet résultatselect = unenoncésql.executequery ("SELECT noclient, nomclient "+ "FROM CLIENT " + "WHERE noclient > 40"); Compilation au preparestatement PreparedStatement unenoncésql = uneconnection.preparestatement ("SELECT noclient, nomclient "+ "FROM CLIENT " + "WHERE noclient > 40"); ResultSet résultatselect = unenoncésql.executequery(); Compilation avec paramètres PreparedStatement unenoncésql = uneconnection.preparestatement ("SELECT noclient, nomclient "+ "FROM CLIENT " + "WHERE noclient >?"); unenoncésql.setint(1,40); ResultSet résultatselect = unenoncésql.executequery(); Statement PreparedStatement CallableStatement Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 30
Exécution en lot (batch) sous JDBC 2 // Création d'un PreparedStatement associé à la Connection PreparedStatement unenoncésql = uneconnection.preparestatement ("INSERT INTO Client VALUES(?,?,?)"); // Ajout d'un INSERT dans le lot unenoncésql.setint(1,90); unenoncésql.setstring(2,"edgar Degas"); unenoncésql.setstring(3,"(222)222-2222"); unenoncésql.addbatch(); // Ajout d'un autre INSERT dans le lot unenoncésql.setint(1,100); unenoncésql.setstring(2,"claude Monet"); unenoncésql.setstring(3,"(111)111-1111"); unenoncésql.addbatch(); // Exécution du lot en un appel int [] résultats = unenoncésql.executebatch(); Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 31
Exécution d'une procédure ou fonction stockée (CallableStatement) // Création d'un appel de fonction associé à la Connection CallableStatement uncall = uneconnection.preparecall("{? = call fquantitéenstock(?)}"); // Spécification du paramètre d'entrée uncall.setint(2,10); // Inscription de la sortie uncall.registeroutparameter(1, java.sql.types.integer); // Exécution de l'appel uncall.execute(); // Récupération de la sortie int laquantite = uncall.getint(1); System.out.println("Quantité en stock :"+laquantite); }; uncall.close(); uneconnection.close(); Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 32
Appel de procédure stockée CallableStatement uncall = uneconnection.preparecall("{call pmodifierquantitéenstock(?,?)}"); // Spécification des paramètres d'entrée uncall.setint(1,10); uncall.setint(2,20); // Exécution de l'appel uncall.execute(); uncall.close(); uneconnection.close(); Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 33
Gestion des transactions Par défaut : auto-commit Pour modifier uneconnection.setautocommit(false); Pour un commit explicite : uneconnection.commit(); Pour un rollback : uneconnection.rollback(); Département de génie logiciel et des TI R. Godin, C. Desrosiers - Hiver 2011 34