• Aucun résultat trouvé

Transparents(PowerPoint)

N/A
N/A
Protected

Academic year: 2022

Partager "Transparents(PowerPoint)"

Copied!
69
0
0

Texte intégral

(1)

5 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

(2)

27/02/22 © Robert Godin. Tous droits réservés .

2

Interface programmatique (Call- Level Interface - SQL/CLI)

API spécifique au SGBD

e.g. Oracle Call Interface

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

(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, …, JSQL

 Moins portable

– pré-compilateur spécifique au SGBD

– traduit en API du SGBD

SQLJ (partie 0) traduit en API standard JDBC

(4)

27/02/22 © Robert Godin. Tous droits réservés .

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

(5)

Routine invoquée en SQL

 Stockée dans le schéma relationnel

 Exécutée au niveau du serveur de BD

 Langage

– SQL/PSM

– SQLJ (partie 1) : routines stockées en

Java

(6)

27/02/22 © Robert Godin. Tous droits réservés .

6

5.1SQL enchâssé

 Syntaxe

 Insertion d'une ligne dans la table Client

EXEC SQL opérationSQLEnchâssée END-EXEC {«;» en C}

EXEC SQL INSERT INTO Client

VALUES (100, 'G. Lemoyne-Allaire', '911');

(7)

Variables partagées

 Déclaration

 Utilisation de variables partagées

 Vérification d ’exceptions avec SQLSTATE

scanf("%d%s%s",&no,nom,tel);

EXEC SQL INSERT INTO Client VALUES (:no, :nom, :tel);

EXEC SQL BEGIN DECLARE SECTION;

int no;

char nom[15];

char tel[15];

char SQLSTATE[6];

EXEC SQL END DECLARE SECTION;

If(strcmp(SQLSTATE, "xxxxx"))…

(8)

27/02/22 © Robert Godin. Tous droits réservés .

8

5.1.1 SELECT à ligne unique

EXEC SQL SELECT nomClient, noTelephone INTO :nom, :tel

FROM Client

WHERE noClient = 10;

printf("Nom: %s Téléphone: %s",nom, tel);

(9)

5.1.2 Curseur SQL

void iterateurClient() {

/* Déclaration des variables partagées*/

EXEC SQL BEGIN DECLARE SECTION;

int no;

char nom[15];

char SQLSTATE[6];

EXEC SQL END DECLARE SECTION;

/*Déclaration du curseur*/

EXEC SQL DECLARE curseurClient CURSOR FOR

SELECT noClient, nomClient FROM Client WHERE noClient > 40;

/*Déclenchement de l'opération SQL*/

EXEC SQL OPEN curseurClient;

while(1){

/*Extraction de la ligne suivante*/

EXEC SQL FETCH FROM curseurClient INTO :no, :nom;

if(/* test de fin de table */

!strcmp(SQLSTATE, « 02000 »)) break;

/* traitement utilisant les variables partagées no et nom*/

}

/*Fermeture du curseur*/

EXEC SQL CLOSE curseurClient;

(10)

27/02/22 © Robert Godin. Tous droits réservés .

10

5.1.3 Mises à jour par curseur

void iterateurModifieurArticle () {

/* Déclaration des variables partagées*/

EXEC SQL BEGIN DECLARE SECTION;

float prix;

char SQLSTATE[6];

EXEC SQL END DECLARE SECTION;

/*Déclaration du curseur*/

EXEC SQL DECLARE curseurArticle CURSOR FOR SELECT prixUnitaire FROM Article FOR UPDATE;

/*Déclenchement de l'opération SQL*/

EXEC SQL OPEN curseurArticle;

while(1){

/*Extraction de la ligne suivante*/

EXEC SQL FETCH FROM curseurArticle INTO :prix;

if(/* test de fin de table */

!strcmp(SQLSTATE, "02000")) break;

if(prix > 25.0)

EXEC SQL DELETE FROM Article

WHERE CURRENT OF curseurArticle ; Else

EXEC SQL UPDATE Article

SET prixUnitaire = prixUnitaire * 1.1 WHERE CURRENT OF curseurArticle ; }

/*Fermeture du curseur*/

EXEC SQL CLOSE curseurArticle;

};

(11)

5.1.4 SQL dynamique

Char chaineSource[…];

printf("Entrez une opération SQL");

scanf("%s", chaineSource);

EXEC SQL PREPARE operationSQL FROM :chaineSource;

EXEC SQL EXECUTE operationSQL ;

(12)

27/02/22 © Robert Godin. Tous droits réservés .

12

5.1.5 Connexion (CONNECT)

R é s e a u

L o g i c i e l i n t e r m é d i a i r e

P i l o t e d e

t é l é c o m m u n i c a t i o n P r o g r a m m e d 'a p p l i c a t i o n

L o g i c i e l i n t e r m é d i a i r e

P i l o t e d e

t é l é c o m m u n i c a t i o n S G B D S Q L

C l i e n t S e r v e u r

B D

(13)

Suite

 Syntaxe du CONNECT

 Exemple avec SQL enchâssé en C

 Pour passer d ’un connexion à l ’autre

 Pour terminer une connexion

CONNECT TO{[ nomServeur [AS nomConnexion]

[USER authorizationID]]|DEFAULT}

EXEC SQL CONNECT TO labunix USER toto ;

SET CONNECTION {[ nomConnexion]|DEFAULT}

DISCONNECT {[nomConnection]|CURRENT|ALL}

(14)

27/02/22 © Robert Godin. Tous droits réservés .

14

5.2 Introduction à l'extension procédurale PL/SQL D'Oracle

PROCEDURE pStatutCommande

(leNoCommande Commande.noCommande%TYPE ) IS -- Déclaration de variables

leNoClient Client.noClient%TYPE;

laDateCommande Commande.dateCommande%TYPE ; leNoArticle Article.noArticle%TYPE ; laQuantitéCommandée LigneCommande.quantité%TYPE ; laQuantitéLivrée INTEGER;

laQuantitéEnAttente INTEGER;

-- Déclaration d'un curseur (CURSOR) PL/SQL pour itérer sur les lignes

-- de la commande

CURSOR lignesCommande(unNoCommande Commande.noCommande%TYPE)IS SELECT noArticle, quantité

FROM LigneCommande

WHERE LigneCommande.noCommande = unNoCommande ; BEGIN

DBMS_OUTPUT.PUT_LINE('Commande #:'||TO_CHAR(leNoCommande));

SELECT noClient, dateCommande INTO leNoClient, laDateCommande FROM Commande

WHERE noCommande = leNoCommande;

DBMS_OUTPUT.PUT_LINE('noClient:'||TO_CHAR(leNoClient));

DBMS_OUTPUT.PUT_LINE('dateCommande:'||TO_CHAR(laDateCommande));

(15)

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

DBMS_OUTPUT.PUT('noArticle :');

DBMS_OUTPUT.PUT(leNoArticle);

DBMS_OUTPUT.PUT(' quantité commandée:');

DBMS_OUTPUT.PUT(laQuantitéCommandée);

-- Chercher la quantité déjà livrée SELECT SUM(quantitéLivrée) INTO laQuantitéLivrée FROM DétailLivraison

WHERE noArticle = leNoArticle AND noCommande = leNoCommande ; 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 ; END LOOP;

-- Le CLOSE ferme le CURSOR CLOSE lignesCommande;

EXCEPTION

WHEN NO_DATA_FOUND THEN

DBMS_OUTPUT.PUT_LINE('Numéro de commande inexistant');

WHEN OTHERS THEN

RAISE_APPLICATION_ERROR(-20001,'Exception levée par la procédure');

(16)

27/02/22 © Robert Godin. Tous droits réservés .

16

Compilation et stockage dans le schéma avec SQL*plus

SQL> CREATE PROCEDURE pStatutCommande

2 (leNoCommande Commande.noCommande%TYPE ) IS 3 4 -- Déclaration de variables

5 leNoClient Client.noClient%TYPE;

6 laDateCommande Commande.dateCommande%TYPE ; 7 leNoArticle Article.noArticle%TYPE ;

8 laQuantitéCommandée LigneCommande.quantité%TYPE ; 9 laQuantitéLivrée INTEGER;

10 laQuantitéEnAttente INTEGER;

11

69 EXCEPTION

70 WHEN NO_DATA_FOUND THEN

71 DBMS_OUTPUT.PUT_LINE('Numéro de commande inexistant');

72 WHEN OTHERS THEN

73 RAISE_APPLICATION_ERROR(-20001,'Exception levée par la procédure');

74 END pStatutCommande;

75 /

Procedure created.

(17)

Appel de la procédure avec SQL*plus

SQL> SET SERVEROUTPUT ON

SQL> EXECUTE pStatutCommande(2);

Commande #:2

noArticle :40 quantité :2 livraison complétée noArticle :95 quantité :3 quantité en attente :2 PL/SQL procedure successfully completed.

SQL> EXECUTE pStatutCommande(5);

Commande #:5

noArticle :10 quantité :5 livraison en attente noArticle :20 quantité :5 livraison en attente noArticle :70 quantité :3 quantité en attente :1 PL/SQL procedure successfully completed.

SQL> EXECUTE pStatutCommande(10);

Commande #:10

Numéro de commande inexistant

PL/SQL procedure successfully completed.

(18)

27/02/22 © Robert Godin. Tous droits réservés .

18

5.2.1 Bloc PL/SQL

[DECLARE

déclaration [déclaration] ...]

BEGIN

séquenceEnoncés [EXCEPTION

exception_énoncé [exception_énoncé] ...]

END

(19)

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.

(20)

27/02/22 © Robert Godin. Tous droits réservés .

20

5.2.2 Déclaration de variables PL/SQL (DECLARE)

leNoClient Client.noClient%TYPE;

leNoClient INTEGER;

(21)

5.2.3 Transfert d'une valeur de colonne d'un SELECT dans une variable (clause INTO)

SELECT noClient, dateCommande

INTO leNoClient, laDateCommande FROM Commande

WHERE noCommande = leNoCommande;

(22)

27/02/22 © Robert Godin. Tous droits réservés .

22

5.2.4 Affectation en PL/SQL

laQuantitéEnAttente:= laQuantitéCommandée -laQuantitéLivrée;

(23)

5.2.5 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 ;

(24)

27/02/22 © Robert Godin. Tous droits réservés .

24

5.2.6 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 ;

(25)

5.2.7 Traitement d'exception (EXCEPTION, RAISE)

 Déclarer

 Soulever

 Attraper

nomException EXCEPTION;

RAISE nomException

WHEN nomException THEN

séquenceÉnoncés

(26)

27/02/22 © Robert Godin. Tous droits réservés .

26

5.2.8 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;

(27)

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;

(28)

27/02/22 © Robert Godin. Tous droits réservés .

28

5.2.9 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

(29)

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

(30)

27/02/22 © Robert Godin. Tous droits réservés .

30

5.2.9.1 PRIVILÈGES DANS UNE ROUTINE STOCKÉE

 Privilèges de l'appelant (invoker rights)

 Privilèges de la routine (definer rights)

– privilèges du créateur

– par défaut

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;

(31)

Exemple privilège de l’appelant

(32)

27/02/22 © Robert Godin. Tous droits réservés .

32

Exemple privilège du créateur

(33)

Exemple privilège du créateur

(suite)

(34)

27/02/22 © Robert Godin. Tous droits réservés .

34

5.2.10 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

(35)

5.2.11 Déboguage du code PL/SQL

SHOW ERRORS sous SQL*plus

Package DBMS_OUTPUT

Table USER_SOURCE dans la métabase

SQL> SELECT text 2 FROM USER_SOURCE

3 WHERE name = 'FQUANTITÉENSTOCK' AND type = 'FUNCTION' 4 ORDER BY line;

TEXT

--- ---

FUNCTION fQuantitéEnStock

(unNoArticle Article.noArticle%TYPE) RETURN Article. quantitéEnStock%TYPE IS

uneQuantitéEnStock Article.quantitéEnStock%TYPE;

BEGIN

SELECT quantitéEnStock INTO uneQuantitéEnStock FROM Article

WHERE noArticle = unNoArticle;

RETURN uneQuantitéEnStock;

TEXT

--- ---

END fQuantitéEnStock;

(36)

27/02/22 © Robert Godin. Tous droits réservés .

36

5.3 JDBC

 API standard pour JAVA

 http://java.sun.com/products/jdbc/

 Ensemble de classes

 Besoin d ’installer un pilote JDBC

dans l ’environnement JAVA

(37)

5.3.1 Architecture pour les pilotes JDBC

A P I J D B C T y p e 1

P a s s e r e l l e J D B C - O D B C

A p p l i c a t i o n J a v a ( i m p o r t j a v a . s q l . * )

T y p e 2 P a r t i e J a v a P i l o t e O D B C

( e . g . p i l o t e O D B C O r a c l e )

T y p e 3 P i l o t e J D B C

g é n é r i q u e T y p e 4

P i l o t e J D B C t o u t J a v a

( e . g . O r a c l e t h i n )

S e r v e u r J D B C A P I c l i e n t d u

S G B D ( e . g . o c i j d b c 8 . d l l

p o u r O r a c l e )

S e r v e u r d e B D

T y p e ? O r a c l e s e r v e r -

s i d e t h i n e t i n t e r n a l d r i v e r

(38)

27/02/22 © Robert Godin. Tous droits réservés .

38

5.3.2 Chargement d'un pilote JDBC

(DriverManager) et établissement d'une connexion (Connection)

 Charger les pilotes JDBC d ’ Oracle

N.B. La librairie des pilotes Oracle doit être accessible à la machine virtuelle Java. Voir http://www.info.uqam.ca/~godin/livres.html

Avec JDK 1.1 (problème avec bloc statique) utiliser :

DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver());

Établir une connexion avec le pilote OCI8 pour un serveur Oracle local

OCI8 est un pilote de type 2

Voir aussi interface javax.sql.DataSource (chap. 15)

package optionnel de JDBC 2

meilleure transparence, plus grande versatilité

maintenant préférée à DriverManager

obligatoire avec J2EE

Class.forName ("oracle.jdbc.driver.OracleDriver");

Connection uneConnection =

DriverManager.getConnection

("jdbc:oracle:oci8:@", "toto", "secret");

(39)

5.3.3 Création d ’un

énoncé SQL (Statement)

Statement

executeQuery(arg0 : String) : ResultSet executeUpdate(arg0 : String) : 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 getFetchDirection() : int

setFetchSize(arg0 : int) : void getFetchSize() : int

getResultSetConcurrency() : int getResultSetType() : int addBatch(arg0 : String) : void clearBatch() : void

executeBatch() : int[]

<<Interface>>

Statement unEnoncéSQL = uneConnection.createStatement ();

(40)

27/02/22 © Robert Godin. Tous droits réservés .

40

5.3.4 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();

} }

(41)

5.3.6 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);

} } }

(42)

27/02/22 © Robert Godin. Tous droits réservés .

42

5.3.7 ResultSet défilable (scrollable), modifiable (updatable), sensible

(sensitive) - JDBC2

//Positionnement à la première ligne du ResultSet résultatSelect.first();

// Positionnement à la dernière ligne du ResultSet résultatSelect.last();

// Positionnement à la troisième ligne résultatSelect.absolute(3);

// Positionnement relatif (avancer de 2 lignes) résultatSelect.relative(2);

// Positionnement à la ligne précédente résultatSelect.previous();

// Création d'un énoncé avec ResultSet défilable (srollable) Statement unEnoncéSQL =

uneConnection.createStatement(

ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);

// Exécution d'un SELECT

ResultSet résultatSelect = unEnoncéSQL.executeQuery ("SELECT noClient, nomClient FROM CLIENT");

(43)

ResultSet modifiable (updatable)

// Création d'un énoncé avec ResultSet défilable (srollable) Statement unEnoncéSQL =

uneConnection.createStatement(

ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);

// Exécution d'un SELECT

ResultSet résultatSelect = unEnoncéSQL.executeQuery ("SELECT noClient, nomClient, noTéléphone FROM CLIENT");

// Exemples de mises-à-jour par ResultSet updatable //Positionnement à la première ligne du ResultSet résultatSelect.first();

// Mise-à-jour de la colonne noTéléphone de la ligne courante résultatSelect.updateString("noTéléphone","(111)111-1111");

// Effectuer le UPDATE résultatSelect.updateRow();

// Positionnement à la dernière ligne de la table résultatSelect.last();

// Supprimer la ligne courante résultatSelect.deleteRow();

// Insertion d'une nouvelle ligne résultatSelect.moveToInsertRow();

résultatSelect.updateInt("noClient", 100);

résultatSelect.updateString("nomClient", "G. Lemoyne-Allaire");

résultatSelect.updateString("noTéléphone", "911");

mises à jour susceptibles

d ’être vues pas le ResultSet

(44)

27/02/22 © Robert Godin. Tous droits réservés .

44

5.3.8 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();

(45)

5.3.9 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();

(46)

27/02/22 © Robert Godin. Tous droits réservés .

46

5.3.10Gestion des transactions

 Par défaut : auto-commit

 Pour modifier

 Pour un commit explicite :

 Pour un rollback :

uneConnection.setAutoCommit(false);

uneConnection.commit();

uneConnection.rollback();

(47)

Suite

 Changer le niveau d ’isolation de défaut

 Transactions réparties JDBC 2

Java Transaction API (JTA)

interface UserTransaction

begin(), commit() – voir chap. 15

uneConnection.setTransactionIsolationLevel(unNiveau) ;

(48)

27/02/22 © Robert Godin. Tous droits réservés .

48

5.3.11Gestion des exceptions

try

{Class.forName ("oracle.jdbc.driver.OracleDriver");

}

catch(ClassNotFoundException e)

{System.err.println(" ClassNotFoundException:" + e.getMessage());

}

 Mécanisme try/catch de JAVA

(49)

5.3.12 Utilisation de JDBC dans une applette Java

 Déploiement avec le pilote thin

 Contrainte de carré de sable

 Exemple

http://www.labunix.uqam.ca/~r11340/ExemplesAppletJDBC/PageAppletJDB C.html

(50)

Exemple d ’applette avec pilote JDBC type 4 (thin)

import java.awt.*;

import java.applet.*;

import java.sql.*;

public class AppletJDBC extends Applet { public void paint (Graphics g)

//N.B. On ne peut lancer (throw) des exceptions non déclarées dans le paint() de Applet...

//Pour simplifier l'exemple, il n'y a qu'un seul try pour tous les appels à JDBC {

try{

// NB Charger le pilote JDBC d'Oracle avec DriverManager pour Java 1.1 sous Explorer 5 DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver());

// Connection à une BD à distance avec un pilote thin Connection uneConnection =

DriverManager.getConnection ("jdbc:oracle:thin:@arabica.cafe.uqam.ca:1521:o8db", "r11340", "motDePasse");

// Création d'un énoncé associé à la Connection

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

g.drawString("Résultat du SELECT :", 5,15);

g.drawString("Numéro", 5,30); g.drawString("Nom", 100,30);

int i = 1;

while (résultatSelect.next ()){

int noClient = résultatSelect.getInt ("noClient");

String nomClient = résultatSelect.getString ("nomClient");

g.drawString(""+noClient,5,i*15+30);

g.drawString(""+nomClient,100,i*15+30);

i = i+1;

}

// Fermeture de l'énoncé et de la connexion unEnoncéSQL.close();

uneConnection.close();

}

catch(Exception e){System.err.println(" Exception:" + e.getMessage());}

} }

(51)

5.3.13 Compilation et exécutions multiples avec la classe PreparedStatement

Statement unEnoncéSQL = uneConnection.createStatement();

ResultSet résultatSelect = unEnoncéSQL.executeQuery ("SELECT noClient, nomClient "+

"FROM CLIENT " +

"WHERE noClient > 40");

PreparedStatement unEnoncéSQL = uneConnection.prepareStatement ("SELECT noClient, nomClient "+

"FROM CLIENT " +

"WHERE noClient > 40");

ResultSet résultatSelect = unEnoncéSQL.executeQuery();

PreparedStatement unEnoncéSQL = uneConnection.prepareStatement ("SELECT noClient, nomClient "+

"FROM CLIENT " +

"WHERE noClient > ?");

unEnoncéSQL.setInt(1,40);

ResultSet résultatSelect = unEnoncéSQL.executeQuery();

 Compilation + exécution combinée au executeQuery

 Compilation au prepareStatement

 Compilation avec paramètres

CallableStatement PreparedStatement

Statement

(52)

27/02/22 © Robert Godin. Tous droits réservés .

52

5.3.14 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();

(53)

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();

(54)

27/02/22 © Robert Godin. Tous droits réservés .

54

5.3.15 Accès aux méta- données (MetaData)

ResultSet résultatSelect = unEnoncéSQL.executeQuery ("SELECT noClient, nomClient "+

"FROM CLIENT " +

"WHERE noClient > 40");

// Consultation de quelques méta-données du ResultSetMetaData ResultSetMetaData unRSMD = résultatSelect.getMetaData();

int nombreColonnes = unRSMD.getColumnCount();

System.out.println("Le résultat du SELECT contient "+nombreColonnes+" colonnes");

for (int indice = 1; indice <= nombreColonnes; indice++){

System.out.println("La colonne "+indice+

" qui se nomme "+unRSMD.getColumnName(indice)+

" est de type "+unRSMD.getColumnTypeName(indice));

Le résultat du SELECT contient 2 colonnes

La colonne 1 qui se nomme NOCLIENT est de type NUMBER

La colonne 2 qui se nomme NOMCLIENT est de type VARCHAR2

(55)

DatabaseMetaData

// Consultation de quelques méta-données de la BD DatabaseMetaData unDBM = uneConnection.getMetaData();

System.out.println("Nom du SGBD :"+unDBM.getDatabaseProductName());

System.out.println("Version du SGBD :"+unDBM.getDatabaseProductVersion());

System.out.println("Niveau d'isolation par défaut :"+unDBM.getDefaultTransactionIsolation());

System.out.println("Support du niveau entrée de SQL2 :"+unDBM.supportsANSI92EntryLevelSQL());

System.out.println("Nom du pilote JDBC :"+unDBM.getDriverName());

Nom du SGBD :Oracle

Version du SGBD :Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production With the Partitioning option

JServer Release 8.1.7.0.0 - Production Niveau d'isolation par défaut :2

Support du niveau entrée de SQL2 :true

Nom du pilote JDBC :Oracle JDBC driver

(56)

27/02/22 © Robert Godin. Tous droits réservés .

56

5.4 SQLJ

 Partie 0 de SQLJ

– SQL enchâssée en Java

 Partie 1 de SQLJ

– Routines stockées

 Partie 2 de SQLJ

– Utilisation de classes Java en tant

que types SQL

(57)

5.4.1 SQL enchâssé en Java (SQLJ : partie 0)

 Ne vise que le statique

 Traduit en JDBC

 Peut combiner SQLJ et JDBC

#sql "{" énoncéSQL "}" ;

#sql {INSERT INTO CLIENT VALUES (100, 'G. Lemoyne-Allaire', '911')};

#sql {DELETE FROM CLIENT WHERE noClient = 10};

(58)

27/02/22 © Robert Godin. Tous droits réservés .

58

Variables partagées

Int no;

String nom;

String tel;

#sql {INSERT INTO CLIENT VALUES (:no, :nom, :tel)};

(59)

5.4.1.1 CONTEXTE DE CONNEXION

//Exemple d'insertion d'un Client avec SQLJ package ExemplesSQLJ;

import sqlj.runtime.*;

import sqlj.runtime.ref.*;

import java.sql.*;

public class ClientInsertSQLJ{

public static void main (String args [])

throws SQLException, ClassNotFoundException, java.io.IOException { // Charger le pilote JDBC d'Oracle

Class.forName ("oracle.jdbc.driver.OracleDriver");

// Création du contexte de connexion de défaut avec autocommit (true) DefaultContext unContexte = new DefaultContext

("jdbc:oracle:thin:@localhost:1521:ora817i", "godin", "oracle", true);

DefaultContext.setDefaultContext(unContexte);

// Insertion en utilisant le contexte de défaut

#sql {INSERT INTO CLIENT VALUES (100, 'G. Lemoyne-Allaire', '911')};

// Fermeture du contexte de connexion unContexte.close();

System.out.println("Insertion réussie !");

}

Contexte implicite

(60)

27/02/22 © Robert Godin. Tous droits réservés .

60

Contexte explicite

// Déclaration de la classe du contexte explicite

#sql context Contexte;

public class ContexteExpliciteSQLJ{

public static void main (String args [])

throws SQLException, ClassNotFoundException, java.io.IOException {

// Charger le pilote JDBC d'Oracle

Class.forName ("oracle.jdbc.driver.OracleDriver");

// Création du contexte de connexion avec autocommit (true) Contexte unContexte = new Contexte

("jdbc:oracle:thin:@localhost:1521:ora817i", "godin", "oracle", true);

// Insertion en utilisant le contexte explicite unContexte

#sql [unContexte] {INSERT INTO CLIENT VALUES (100, 'G. Lemoyne-Allaire', '911')};

(61)

Commit explicite

// Création du contexte de connexion de défaut sans autocommit (false) DefaultContext unContexte = new DefaultContext

("jdbc:oracle:thin:@localhost:1521:ora817i", "godin", "oracle", false);

DefaultContext.setDefaultContext(unContexte);

// Insertion en utilisant le contexte de défaut

#sql {INSERT INTO CLIENT VALUES (100, 'G. Lemoyne-Allaire', '911')};

// Confirmer la transaction #sql {COMMIT};

(62)

27/02/22 © Robert Godin. Tous droits réservés .

62

5.4.1.3 SELECT QUI RETOURNE UN SINGLETON (CLAUSE INTO)

String nom;

String tel;

// Utilisation de la clause INTO

#sql { SELECT nomClient, noTéléphone INTO :nom, :tel

FROM Client WHERE noClient = 10};

(63)

5.4.1.4 ITÉRATEUR DE RÉSULTAT SQLJ

// Définition de la classe IteratorClient avec liaison par nom #sql iterator IteratorClient(int noClient, String nomClient);

// Création d'un objet itérateur IteratorClient unIteratorClient;

// Liaison de l'énoncé SELECT de l'itérateur #sql unIteratorClient =

{ SELECT noClient, nomClient

FROM Client WHERE noClient > 40};

// Accès au résultat du SELECT par itération sur les lignes while (unIteratorClient.next()){

System.out.println("Numéro du client : " + unIteratorClient.noClient());

System.out.println("Nom du client : " + unIteratorClient.nomClient());

}

// Fermer l'itérateur unIteratorClient.close();

(64)

27/02/22 © Robert Godin. Tous droits réservés .

64

Mise-à-jour par itérateur

// Définition de la classe IteratorClient avec liaison par nom #sql iterator IteratorClient implements sqlj.runtime.ForUpdate (int noClient, String nomClient);

// Création d'un objet itérateur IteratorClient unIteratorClient;

// Liaison de l'énoncé SELECT de l'itérateur #sql unIteratorClient =

{ SELECT noClient, nomClient, noTéléphone FROM Client WHERE noClient > 40};

// Accès au résultat du SELECT par itération sur les lignes while (unIteratorClient.next()){

if (unIteratorClient.noClient()== 60){

#sql {UPDATE Client

SET noTéléphone = '(111)111-1111' WHERE CURRENT of :unIteratorClient};

} else if (unIteratorClient.noClient()== 80){

#sql {DELETE FROM Client

WHERE CURRENT of :unIteratorClient};

}

(65)

5.4.1.5 APPEL DE ROUTINES STOCKÉES EN SQLJ

int laQuantite = 0;

int noArticle = 10 ;

// Appel de la fonction stockée

#sql laQuantite = {VALUES (fQuantitéEnStock(:noArticle))};

// Fermeture du contexte de connexion unContexte.close();

System.out.println("Quantité en stock :" + laQuantite); }

// Appel de la procédure stockée

#sql {CALL pModifierQuantitéEnStock(:in noArticle,:in laQuantite)};

(66)

27/02/22 © Robert Godin. Tous droits réservés .

66 Connection uneConnection =

DriverManager.getConnection

("jdbc:oracle:thin:@localhost:1521:ora817i", "godin", "oracle");

Contexte unContexte = new Contexte(uneConnection);

5.4.1.6 INTEROPÉRABILITÉ AVEC JDBC

Création d'un contexte SQLJ à partir d'une Connection JDBC

Extraction de la Connection d'un contexte

Conversion d'un itérateur en un ResultSet JDBC

Conversion d'un ResultSet JDBC en un iterateur SQLJ

Connection uneConnection = unContexte.getConnection();

ResultSet résultatSelect = unIteratorClient.getResultSet();

#sql unIteratorClient = {CAST :unResultSet};

(67)

5.4.1.7 PROCESSUS DE TRADUCTION SQLJ

S c h é m a S Q L

N o m C l a s s e . S Q L J

T r a d u c t e u r S Q L J ( p a r t i e 0 )

N o m C l a s s e . J a v a

N o m C l a s s e _ S J P r o f i l e 0 . s e r N o m C l a s s e _ S J P r o f i l e 1 . s e r

. . .

C o m p i l a t e u r J a v a

N o m C l a s s e . c l a s s C l a s s e s d e l '

e n v i r o n n e m e n t d 'e x é c u t i o n S Q L J

F i c h i e r d e d é p l o i e m e n t ( . j a r )

A d a p t a t i o n s p é c i f i q u e à u n

(68)

27/02/22 © Robert Godin. Tous droits réservés .

68

5.4.2 SQLJ partie 1: routines stokées en Java

import java.sql.*;

import java.io.*;

public class RoutineServeur extends Object {

public static int getQuantiteEnStock (int noArticle) throws SQLException {

// Retourne -1 si l'article n'existe pas PreparedStatement unEnoncéSQL = null;

int quantitéEnStock = -1;

try {

Connection uneConnection =

DriverManager.getConnection("jdbc:default:connection:");

unEnoncéSQL = uneConnection.prepareStatement

("SELECT quantitéEnStock FROM Article WHERE noArticle = ? ");

unEnoncéSQL.setInt(1,noArticle);

ResultSet résultatSelect = unEnoncéSQL.executeQuery();

if (résultatSelect.next ()){

quantitéEnStock = résultatSelect.getInt(1);

} }

catch (SQLException e) {System.err.println(e.getMessage());}

finally{unEnoncéSQL.close();}

return quantitéEnStock;

}

public static void setQuantiteEnStock (int noArticle, int quantitéEnStock) throws SQLException {

PreparedStatement unEnoncéSQL = null;

try {

Connection uneConnection =

DriverManager.getConnection("jdbc:default:connection:");

unEnoncéSQL = uneConnection.prepareStatement

("UPDATE Article SET quantitéEnStock = ? WHERE noArticle = ? ");

unEnoncéSQL.setInt(1,quantitéEnStock);

unEnoncéSQL.setInt(2,noArticle);

unEnoncéSQL.executeUpdate();

}

catch (SQLException e) {System.err.println(e.getMessage());}

finally{unEnoncéSQL.close();}

} }

(69)

Déploiement Oracle

 Charger le code dans un schéma

 Publier sous forme de routine stockée :

 Appeler la fonction en SQL

loadjava -user godin/oracle RoutineServeur.class

SQL> CREATE OR REPLACE FUNCTION getQuantiteEnStock(noArticle NUMBER) 2 RETURN NUMBER

3 AS LANGUAGE JAVA

4 NAME ' RoutineServeur.getQuantiteEnStock (int) return int';

5 /

Function created.

SQL> select getQuantiteEnStock(10) from dual;

GETQUANTITEENSTOCK(10) --- 20

Références

Documents relatifs

Les unités des différentes grandeurs doivent toujours être compatibles entre elles

De fait, l'“impeto” contient deux idées originales dont l'importance allait s'avérer décisive : la conservation du mouvement, plus précisément de la quantité de mouvement

On utilise ce principe variationnel pour d´ eriver la loi de conservation de la quantit´ e de mouvement pour le syst` eme Maxwell-Vlasov avec la r´ eduction gyrocin´ etique.. Il

Le marchand : Alors, un kilo de carottes, trois melons et deux kilos de pommes de terre.. Douze

Pour chaque OTC avec une date de demande de juin 2010, afficher les informations : NUM_OTC (Numéro OTC), NUMVELIB (Numéro de Vélib), NOM_MODELE (Nom du Modèle) et NOM_AGENT (Nom

Les levures dégradent (oxydent) le glucose et le saccharose mais pas le lactose La réaction est moins rapide pour le saccharose car la molécule trop volumineuse pour pénétrer

Figure B - Spectres d’absorption de la solution de 2’-hydroxyacétophénone (1) (en rouge, trait plein, notée acétophénone sur la figure), de la solution du dérivé boré (4)

Opening the cursor allocates memory for the cursor and makes it ready for fetching the rows returned by the SQL statement into it. For example, we will open above-defined cursor