Télécharger la présentation
La présentation est en train de télécharger. S'il vous plaît, attendez
1
Interface langage hôte PRO*C
2
Principe des langages hôtes
Le code SQL est encapsulé dans le programme Création d ’un premier programme appelé pré-source contenant le code du langage et le code SQL Appel d ’un pré-compilateur qui traduit les ordres SQL en ordres du langage hôte Compilation, édition de liens (avec les bibliothèques SQL) et création du programme client exécutable Deux types d ’erreur possibles : erreurs SQL lors de l ’étape de pré-compilation (n° de ligne du pré-source) erreurs du langage hôte lors de la compilation (n° de de ligne du source généré)
3
Création du programme exécutable
Editeur prog prog.pc EXEC SQL… EXEC SQL… Pré-compilateur Correction dans .pc Edition de liens prog.c Recherche erreurs Erreurs SQL Bibliothèques printf(…….); prog.o Erreurs C Compilateur
4
Exemple de programme : connexion et déconnexion à une base locale
/* debut.pc PRO*C : CONNEXION ET DECONNEXION */ #include <stdio.h> #include <ctype.h> #include <string.h> EXEC SQL BEGIN DECLARE SECTION; VARCHAR user[20]; VARCHAR pwd[20]; EXEC SQL END DECLARE SECTION; EXEC SQL INCLUDE sqlca.h; Variables hôtes Zone de communication
5
Exemple de programme (suite)
connection() { /* entrée du mot de passe et du nom */ user.len=asks("Entrer votre user : ",user.arr); pwd.len=asks("Entrer votre pwd : ",pwd.arr); /* connection a la base */ EXEC SQL WHENEVER SQLERROR GOTO erreur; EXEC SQL CONNECT :user IDENTIFIED BY :pwd; printf("\n Connexion réussie \n"); return(1); erreur : printf("\n Erreur a la connexion .... "); errpt(); return(0); EXEC SQL WHENEVER SQLERROR continue; }
6
Exemple de programme (suite 2)
selection() { /* fonction de selection */ printf("\n Debut de selection \n"); } main() { if (connection()) { selection(); sortie(); } else arret(); sortie() { EXEC SQL COMMIT RELEASE; } arret() { EXEC SQL ROLLBACK RELEASE; }
7
Exemple de programme (fin)
int askn(text,variable) char text[]; int *variable; { char s[20]; printf(text); if ( gets(s) == (char *)0 ) return(EOF); *variable = atoi(s); return(1); } int asks(text,variable) char text[],variable[]; { printf(text); return( gets(variable) == (char *)0 ? EOF : strlen(variable) );
8
Structure d’un programme
Le prologue La section DECLARE La section INCLUDE La section CONNECT Le corps Ordres du langage C Ordres SQL EXEC SQL ……….;
9
Déclaration des variables hôte (variables d’échange)
Passages de variables par valeurs entre le programme client et la BD BD Programme (SELECT …. INTO :v1,:v2 …) Programme BD (INSERT …. VALUES (:v1,:v2,….)) Correspondance entre types de variables BD NUMBER(n) NUMBER(n,m) CHAR(n) VARCHAR(n) Pseudo type VARCHAR PRO*C int float char
10
La section DECLARE Présente au début du programme : variables globales
Présente dans une fonction : variables locales EXEC SQL BEGIN DECLARE SECTION; int pno; /* un caractère de + pour la fin de chaîne '\0' */ char pidemp[14]; int pdept; float psal; EXEC SQL END DECLARE SECTION;
11
Le pseudo-type VARCHAR
PRO*C permet l’utilisation du type VARCHAR correspondant au VARCHAR de la base Déclaration dans le programme ‘.pc’ Génération dans le programme ‘.c’ EXEC SQL BEGIN DECLARE SECTION; VARCHAR pnomemp[31]; EXEC SQL END DECLARE SECTION; struct { unsigned int len; unsigned char arr[31]; } pnomemp; longueur de la chaîne chaîne elle même
12
Utilisation des variables VARCHAR BD PRO*C
Bases de données Nom VARCHAR(5); Adresse VARCHAR(10); N°ligne, N°colonne,longueur colonne, valeur colonne ….. Programme pro*c Varchar pnom[6]; Varchar padresse[11]; 1 1 4 Marc 2 8 Toulouse 2 …….. 4 Marc \0 8 Toulouse \0 pnom.len pnom.arr padresse.len padresse.arr pnom.arr[pnom.len]= '\0'; padresse.arr[padresse.len]= '\0';
13
Utilisation des variables VARCHAR PRO*C BD
Programme pro*c VARCHAR pidemp[6]; Lire pidemp.arr Base de données Idemp VARCHAR(5); pidemp.len=strlen(pidemp.arr); 3 100 \0 3 100
14
La section INCLUDE EXEC SQL INCLUDE sqlca.h;
Inclusion dans le programme ‘.c’ d’une zone de communication SQL Communication Area Cette zone est systématiquement remplie après exécution d’un ordre SQL Son contenu permet de savoir si l’ordre s’est bien passé (correct, warning ou erreur)
15
La structure SQLCA (début)
long sqlcode; /*résultat de l’exécution =0 succès, >0 succès avec un code d’état, <0 erreur */ unsigned short sqlerrml; /*longueur*/ char sqlerrmc[70]; /*message erreur*/ }sqlerrm; long sqlerrd[6]; /* seul sqlerrd[2] est utilisé : nombre de lignes ‘touchées’ par un ordre SQL (UPDATE, INSERT, DELETE) ou ramenées par un SELECT ou des FETCH */
16
La structure SQLCA (fin)
char sqlwarn[8]; /* sqlwarn[0]= 'W' présence d'un warning sqlwarn[0]= '' pas de warning sqlwarn[1]= 'W' valeur tronquée sqlwarn[2]= 'W' valeur nulle sqlwarn[3]= 'W' plus de colonnes du select que de variables de réception sqlwarn[4]= 'W' toutes les lignes sont touchées par DELETE ou UPDATE sqlwarn[5]= 'W' inutilisé sqlwarn[6]= 'W' ROLLBACK par Oracle sqlwarn[7]= 'W' dans le cas d’un verrouillage multi-ligne préventif , une ligne a été modifiée avant la fin complète du verrouillage */
17
EXEC SQL CONNECT :user IDENTIFIED BY :pwd;
La section CONNECT Connexion à un compte d’une base Oracle Connexion à une base locale /*Déclaration de 2 variables d’échange user et pwd remplissage de ces 2 variables par lecture ou affectation dans le programme */ EXEC SQL CONNECT :user IDENTIFIED BY :pwd; /* Plusieurs cas possibles : connexion réussie mauvais nom ou mot de passe base non ouverte …. */
18
Connexion à une base distante Client - Serveur
Déclaration d’une variable base de données Connexion à la base distante avec la chaîne de connexion ou ‘chemin’ définie sur le poste client Tous les ordres SQL sont préfixés : EXEC SQL DECLARE mabase1 DATABASE; EXEC SQL CONNECT :user IDENTIFIED BY :pwd AT mabase1 USING :chemin; /* ou 'nom_du_chemin' */ EXEC SQL AT mabase1 SELECT …… INTO ……;
19
L’option WHENEVER SQLERROR
Si erreur sur une instruction EXEC SQL débranchement vers un label Penser à arrêter ce débranchement automatique pour les fonctions suivantes EXEC SQL WHENEVER SQLERROR GOTO erreur; EXEC SQL …………………; erreur : Attention à ne pas continuer en séquence EXEC SQL WHENEVER SQLERROR continue;
20
SELECT MONO-LIGNE WHENEVER NOT FOUND
EXEC SQL SELECT ……. INTO variables hôtes WHENEVER NOT FOUND EXEC SQL SELECT nom,salaire INTO :vnom, :vsalaire FROM emp WHERE idemp = :idemplu; EXEC SQL WHENEVER NOT FOUND GOTO nontrouve; EXEC SQL SELECT nom,salaire INTO :vnom, :vsalaire FROM emp WHERE idemp = :idemplu; nontrouve : Attention à ne pas continuer en séquence
21
SELECT MULTI - LIGNE ‘ CURSEUR ’
Un curseur est une zone mémoire serveur contenant l’ordre de sélection et la ligne courante. Défini par un ‘ déclare ’. Les lignes sélectionnées sont chargées en mémoire sur le serveur à l ’ouverture du curseur au moment de l ’open. Chaque ligne est retournée vers le programme pro*c client avec l ’ordre ‘ fetch ’ en gérant une boucle . Cette boucle est gérée par le WHENEVER NOT FOUND qui se transforme en ‘ LAST ROW RETURNED ’. La zone mémoire et le curseur sont perdues (récupérées) au ‘ close ’ du curseur.
22
Exemple de gestion d ’un curseur : Affichage des employés d ’un service
Déclaration du curseur Entrée du premier id service lu et boucle service Ouverture du curseur : remplissage mémoire Attention : gestion des erreurs sur l ’open EXEC SQL DECLARE c1 CURSOR FOR SELECT nom, salaire FROM emp WHERE idser=:idserlu; idserlu.len=asks("Entrer service : ",idserlu.arr); while(!strcmp(idserlu.arr,"fin") { EXEC SQL OPEN c1;
23
Exemple d ’un curseur (2)
Gestion de la boucle qui ‘ ramène ’ les lignes Boucle Fin de la boucle : récupération place mémoire EXEC SQL WENEVER NOT FOUND GOTO terminé; while(1) { EXEC SQL FETCH c1 INTO :vnom,:vsal; vnom.arr[vnom.len]='\0'; printf( …………….,vnom.arr,vsal); } terminé : EXEC SQL CLOSE c1;
24
Exemple d ’un curseur (3)
Poursuite de la consultation Entrée d ’un id service suivant ou ’fin’ Penser aussi à gérer les erreurs sur le cursor soit : à l ’ouverture OPEN au FETCH idserlu.len=asks("idser ou fin: ",idserlu.arr); }
25
Les variables indicatrices de transfert
A chaque FETCH, on peut savoir la valeur retournée pose problème A chaque variable hôte, on associe une variable indicatrice de transfert déclarée en ’short’ Le contenu de cette variable indique l ’état du transfert : 0 --> aucun problème -1 --> valeur NULLE (NULL) >0 --> valeur tronquée
26
Variables indicatrices : exemple
Déclarations des variables hôtes et indicatrices Utilisation dans le programme Il suffit de tester les variables indicatrices EXEC SQL BEGIN DECLARE SECTION; VARCHAR pnomemp[31]; short ipnomemp; float psal; short ipsal; EXEC SQL END DECLARE SECTION; EXEC SQL FETCH c1 INTO :pnomemp:ipnomemp, :psal:ipsal;
27
Gestion des transactions en pro*c
Même principe que pour les transactions en général Deux déconnexions différentes dans un programme EXEC SQL COMMIT RELEASE ; EXEC SQL ROLLBACK RELEASE; Fin d ’une transaction EXEC SQL COMMIT; EXEC SQL ROLLBACK;
28
Concurrence d ’accès en pro*c
Contrôle de partage simultané en respectant l ’intégrité des données Lecture multi-version cohérente au niveau ligne Plusieurs lectures cohérentes Points de confirmation explicites Verrouillages (implicites ou explicites) au niveau ligne
29
Lecture Multi - Version
Deux manières de voir une ressource : Au début d’une consultation d’une table, Oracle génère une vue fixe ou cliché (snapshot) de cette table Ce cliché est conservé soit en mémoire, soit dans des espaces disques appelés ‘rollback segments’ Ces segments sont utilisés pour : Les reprises avec annulation (ROLLBACK) Assurer la cohérence en lecture Même si la consultation dure longtemps et, malgré des modifications, l’utilisateur ‘verra’ le cliché initial
30
Lecture Multi – Version Exemple
EXEC SQL SELECT SUM(solde) INTO pognon FROM comptes; idcpt solde type_compte /*Début transaction*/ EXEC SQL UPDATE comptes SET solde=solde-1000 WHERE idcpt=100; SET solde=solde+1000 WHERE idcpt=200; EXEC SQL COMMIT; 100 12000 cc 200 500 épargne
31
Lecture Multi – Version (fin)
Les transferts n’affectent en rien le calcul de la somme des comptes –> lecture du cliché Aucun verrou n’est posé en consultation et les verrous posés par les modifications n’empêchent pas la consultation : Une consultation ne bloque pas les autres Une consultation ne bloque pas les mises à jour Une mise à jour ne bloque pas les consultations Dans le cas d’une jointure synchronisée ou certaines lignes d’une tables sont lues plusieurs fois lecture des mêmes valeurs malgré les modifications
32
Plusieurs lectures cohérentes
Consultations multiples : dans un boucle Préciser à Oracle qu’il doit garder le cliché jusqu’à la fin : Le SGBD n’accepte alors que des SELECT COMMIT pour terminer EXEC SQL SET TRANSACTION READ ONLY;
33
Plusieurs lectures cohérentes Exemple
EXEC SQL SET TRANSACTION READ ONLY; Tant_Que (lire code_ufr_lu.arr) EXEC SQL SELECT COUNT(*) INTO :n FROM étudiant WHERE codeufr= :code_ufr_lu; /* Affichage de n */ Fin_Tant_Que EXEC SQL COMMIT;
34
Points de confirmation explicites
Pose de ‘points de sauvegarde’ (savepoint) Découpage d’une transaction par étapes En cas de problème, on ‘défait’ en remontant sur un point de confirmation sans tout défaire Les points sont posés avec la commande Pour défaire, il suffit de préciser le point ou l’on remonte : EXEC SQL SAVEPOINT nom_du_point; EXEC SQL ROLLBACK TO SAVEPOINT nom_du_point;
35
Points de confirmation explicites Exemple
/* Insertions dans client */ EXEC SQL INSERT INTO clients(no,nom,état) VALUES(:num,:nom,:’ACTIF’); …… /* Modifications dans cette table */ EXEC SQL UPDATE clients SET état=:nouvel_état WHERE no=:num; …………… /* Pose d’un point de confirmation */ EXEC SQL SAVEPOINT avant_sup; /Suppressions dans la table clients */ EXEC SQL DELETE FROM clients WHERE état=‘INACTIF’; If (sqlca.sqlerrd[2] < 30 ) {printf("Nombre de lignes supprimées : %d", sqlca.sqlerrd[2]); EXEC SQL COMMIT;} else {printf("Pas de suppression des %d" lignes , EXEC SQL ROLLBACK TO SAVEPOINT avant_sup;
36
Points de confirmation implicites
Versions anciennes d’Oracle : aucun point de confirmation implicite à chaque ordre LMD En cas de problème, Oracle faisait automatiquement le ROLLBACK complet de la transaction ! Aujourd’hui, Oracle pose un point à chaque action, détecte une erreur, le fait savoir à la transaction (SQLCA) qui choisit la suite Attention : le système ne défait plus donc le programmeur doit choisir une stratégie (défaire ou poursuivre)
37
Verrouillage au niveau ligne
Mise à jour globale avec verrouillage implicite Un ordre UPDATE verrouille les lignes ‘touchées’ Libération des verrous au COMMIT Mise à jour ligne par ligne avec verrouillage implicite UPDATE dans une boucle avec libération immédiate Mise à jour par ligne avec verrouillage explicite Verrouillage préventif des lignes AVANT les modifications
38
Mise à jour globale avec verrouillage implicite
L’ordre UPDATE est envoyée à Oracle Fonctionnement : Les lignes sélectionnés sont ‘montées’ en mémoire A la fin du transfert verrouillage des lignes Modifications en mémoire et re-écriture sur disque Le COMMIT libère les verrous EXEC SQL UPDATE emp SET sal=sal*1.1 WHERE service=‘info’; EXEC SQL COMMIT;
39
Mise à jour globale (2) : les problèmes
Pas d’isolation des transactions au moment du transfert en mémoire D’autres transactions peuvent ‘monter’ des mêmes lignes au même moment Chaque transaction fait alors les modifications sur de fausses données Voir Concepts : Intégrité d’une BD
40
Mise à jour par ligne On se sert d’une variable gérée par Oracle contenant l’adresse de la ligne : ROWID Chaque ligne est verrouillée individuellement au moment de l’UPDATE puis libérée par un COMMIT dans la boucle Même inconvénient que tout à l’heure : deux mêmes UPDATE peuvent ‘monter’ une même ligne
41
Mise à jour par ligne : Exemple
EXEC SQL DECLARE CURSOR c1 FOR SELECT nom,salaire,ROWID FROM emp WHERE dept=:dept_lu; /* Lire dept_lu */ EXEC SQL OPEN c1; EXEC SQL WHENEVER NOTFOUND GOTO fin_maj; while(1) { EXEC SQL FETCH c1 INTO :nom,:sal,:id_row; /* Affichage du nom et saisie de l’augmentation */ EXEC SQL UPDATE emp SET salaire=salaire+:aug_lue WHERE ROWID=:id_row; EXEC SQL COMMIT; }
42
Mise à jour par ligne avec verrouillage global préventif
Toutes les lignes sélectionnées sont verrouillées AVANT les mises à jour Tout autre transaction voulant verrouiller les mêmes lignes sera en attente verrouillage exclusif Le système est averti si une autre transaction a modifié une ligne pas encore verrouillée sqlwarn[7] = ‘W’ dans sqlca
43
Verrouillage global préventif : Exemple
EXEC SQL DECLARE CURSOR c1 FOR SELECT nom,salaire FROM emp WHERE dept=:dept_lu FOR UPDATE OF salaire; /* Lire dept_lu */ EXEC SQL OPEN c1; EXEC SQL WHENEVER NOTFOUND GOTO fin_maj; while(1) { EXEC SQL FETCH c1 INTO :nom,:sal; /* Affichage du nom et saisie de l’augmentation */ EXEC SQL UPDATE emp SET salaire=salaire+:aug_lue WHERE CURRENT OF c1; } EXEC SQL COMMIT; Option de verrouillage Chargement et verrouillage
44
Les variables hôtes tableaux
Optimisation des performances en Client-Serveur Diminution du nombre de transfert entre Client et Serveur Sens Client Serveur Une seule requête est envoyée (INSERT ou UPDATE) Les données sont dans un tableau Sens Serveur Client Les lignes sont retournées par ‘paquet’ et stockées dans des tableaux
45
INSERT avec lignes groupées
Déclaration des variables tableaux Remplissage des tableaux dans le programme client nombre de lignes saisies (nbl) Envoi de l’ordre au SGBD EXEC SQL BEGIN DECLARE SECTION; int vnuméro[300]; VARCHAR vnom [300] [30]; EXEC SQL END DECLARE SECTION; EXEC SQL FOR :nbl INSERT INTO emp(no,nom) VALUES(:vnuméro,:vnom); nbl lignes envoyées avec un ordre INSERT
46
UPDATE avec lignes groupées
Déclaration des variables tableaux Saisie et remplissage des tableaux dans le programme client nombre de lignes saisies (nbl) Envoi de l’ordre UPDATE avec les variables tableaux EXEC SQL BEGIN DECLARE SECTION; int videtu[300]; float vnote [300]; EXEC SQL END DECLARE SECTION; EXEC SQL FOR :nbl UPDATE notes SET note=:vnote WHERE idetu=:videtu;
47
Sélection avec tableaux nombre de lignes connu
Le nombre maximum de lignes est connu Si le nombre de ligne dépasse la capacité du tableau erreur SQL (too many rows …) Le SGBD nous permet de connaître le nombre de lignes retournées avec la variable sqlca.sqlerrd[2] de la variable sqlca On peut donc travailler dans les tableaux EXEC SQL SELECT numéro,nom INTO :numéro,:nom WHERE dept=10; for (i=0; i<sqlca.sqlerrd[2]; i++) { /* affichage des éléments */ }
48
Sélection avec tableaux nombre de lignes inconnu
Utilisation obligatoire d’un curseur Déclaration de tableaux de réception inférieurs au nombre de lignes sélectionnées sans problème Chaque FETCH retourne le nombre de lignes correspondant à la dimension des tableaux de réception Le dernier FETCH active le NOT FOUND Le nombre total de lignes est dans sqlca.sqlerrd[2]
49
Sélection avec nombre de lignes inconnu Exemple
Soit une table emp de 700 lignes et des variables de réception de 300 éléments Le dernier FETCH active le NOT FOUND (last row returned) EXEC SQL DECLARE c1 CURSOR FOR SELECT no,nom,salaire FROM emp; EXEC SQL OPEN c1; EXEC SQL FETCH c1 INTO :vno,:vnom,:vsal; --- sqlerrd[2] = 300 --- sqlerrd[2] = 600 --- sqlerrd[2] = 700
50
Bloc PL/SQL dans un programme pro*c
Programmation des transactions Si tout va bien : COMMIT En cas de problème : EXCEPTION avec ROLLBACK Le bloc PL est transféré vers le SGBD avec les paramètres passées par le programme pro*c Le bloc PL est envoyé vers le noyau SQL et exécuté dans son ensemble EXEC SQL EXECUTE DECLARE BEGIN EXCEPTION END-EXEC
51
Bloc PL/SQL embarqué : Transfert de comptes
/* Programme C : Déclarations des variables Hôtes*/ EXEC SQL BEGIN DECLARE SECTION; int ncd; /* compte à débiter */ int ncc; /* compte à créditer */ float somme; /* somme à transférer */ VARCHAR message[81]; EXEC SQL END DECLARE SECTION; askn("Entrer compte à débiter : ",&ncd); askn("Entrer compte à créditer : ",&ncc); askn("Entrer le montant : ",&somme);
52
Bloc PL/SQL embarqué (2)
/* Début du bloc PL*/ EXEC SQL EXECUTE; -- déclarations des variables du bloc DECLARE ligned comptes%ROWTYPE; lignec comptes%ROWTYPE; BEGIN SELECT * INTO ligned FROM comptes WHERE nc=:ncd FOR UPDATE OF solde; SELECT * INTO lignec FROM comptes WHERE nc=:ncc FOR UPDATE OF solde; -- verrouillage préventif des 2 lignes
53
Bloc PL/SQL embarqué (3)
IF ligned.solde - :somme < ligned.découvert_autorisé THEN RAISE solde_insuffisant; END IF; UPDATE comptes SET solde = solde - :somme WHERE nc=:ncd; UPDATE comptes SET solde = solde + :somme WHERE nc=:ncc; INSERT INTO opérations VALUES (………); message:=‘Transaction réussie’; COMMIT; -- Fin normale de Transaction -- Libération des verrous
54
Bloc PL/SQL embarqué (4)
EXCEPTION WHEN solde_insuffisant THEN ROLLBACK; message :=‘Solde insuffisant’; WHEN OTHERS THEN message :=SUBSTR(SQLCODE,1,80); END; END-EXEC; message.arr[message.len]=‘\0’; printf("%s \n",message.arr); /* Suite du programme pro*c */
55
Appels de procédures stockées
Le bloc PL/SQL devient une procédure stockée Appel de la procédure dans le programme pro*c EXEC SQL EXECUTE BEGIN transfert(:ncd,:ncc,:somme,:message); END; END-EXEC; Nom de la procédure
Présentations similaires
© 2024 SlidePlayer.fr Inc.
All rights reserved.