autorise dans un programme C des instructions destinées au précompilateur pcc
PRO*C est une interface entre le langage C et le SGBD ORACLE. Il s'agit d'une interface de précompilation, c'est-à-dire le programmeur écrit ses ordres SQL dans son code C et ceux-ci sont expansés par un précompilateur en appels de fonctions d'une librairie C (pour être aisément décelés dans le source C, tous les appels SQL commencent par "EXEC SQL").
La précompilation, la compilation et l'édition de liens de tels programmes sont masquées par un fichier de type Makefile : proc.mk. Les fichiers sources doivent être suffixés par .pc.
Utilisation : (pour compiler le fichier toto.pc)
make -f proc.mk USERID = login_oracle/motdepasse_oracle toto.exe
Cette commande génère plusieurs fichiers dont notamment un fichier toto.c et un fichier exécutable toto. Il est souvent nécessaire d'aller regarder dans toto.c pour comprendre les messages d'erreurs du compilateur C.
L'organisation générale d'un programme PRO*C est la suivante :
1) une partie prologue :
Dans cette partie le programmeur "prépare" la liaison entre C et ORACLE. Pour cela il déclare un ensemble de variables de communication entre C et ORACLE (dans la DECLARE SECTION), et une zone de communication pour récupérer les comptes rendus ORACLE (la SQLCA). Cette partie comprend également l'ordre de connection à une base ORACLE (CONNECT). Un début de programme indique implicitement un début de transaction.
2) une partie traitement classique :
Les ordres SQL sont intégrés dans le code source C où ils remplacent les instructions d'entrée/sortie classiques.
Il faut également finir la transaction. Celle ci se termine par un COMMIT ou un ROLLBACK explicites.
I) Le prologue :
I-1) Déclaration des variables de communication :
Elle se fait dans la DECLARE SECTION. Celle ci commence par l'ordre
EXEC SQL BEGIN DECLARE SECTION;
et se termine par
EXEC SQL END DECLARE SECTION;
Elle doit comprendre la déclaration de toutes les variables qui sont utilisées dans les ordres SQL et C.
La zone de communication est locale à la procédure qui la définit : chaque procédure peut posséder sa propre zone de communication. De plus le rapport entre variables globales et variables locales est respecté.
Exemple :
EXEC SQL BEGIN DECLARE SECTION;
int pempno ;
char pname[11];
int pdeptno;
EXEC SQL END DECLARE SECTION;
L'utilisation de ces variables dans un ordre SQL
EXEC SQL SELECT DEPTO, ENAME
INTO :pdeptno, :pname FROM EMP
WHERE EMPNO = :pempno;
Les variables de communication sont précédées d'un ":" dans les ordres SQL
L'utilisation dans une instruction C
strcpy(pname,"Martin") ;
Les variables de communication sont utilisées normalement dans les instructions C.
Les types possibles pour ces variables sont ceux compatibles avec ORACLE, c'est à dire entiers, réels, chaînes de caractères (on ne peut utiliser de types définis avec des instructions typedef).
Il existe cependant une extension proposée par ORACLE, qui permet de définir des chaînes de caractères de taille variable (le type VARCHAR).
Exemple :
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR description[40];
EXEC SQL END DECLARE SECTION;
cette définition s'expanse en :
struct { unsigned short int len;
unsigned char arr[40] } description ;
Les variables de ce type s'utilisent normalement dans les ordres SQL, par contre pour leur manipulation dans C, le programmeur doit s'assurer que la taille de la chaine de caractères est bien initialisée. Le cas échéant il doit affecter "variable.len" en effectuant variable.len = strlen(variable.arr);).
I-2) La zone de communication ORACLE :
Une zone de communication (SQLCA) permet au programme de connaître les résultats d'un ordre SQL. Cette zone est une structure C qui doit être incluse dans chaque programme PRO*C par un ordre INCLUDE :
EXEC SQL INCLUDE sqlca.h;
Plusieurs éléments de la structure sont particulièrement intéressants :
- sqlca.sqlerrm.sqlerrmc : contient en cas de problème le numéro et le message d'erreur d'ORACLE.
- sqlca.sqlcode : contient le code retour d'exécution ORACLE. Ce code vaut 0 si l'exécution s'est bien effectuée, a une valeur négative en cas d'erreur, et a une valeur positive pour une exécution réussie mais avec un code de statut (par exemple, fin de curseur),
- sqlca.sqlwarn : c'est un tableau de 8 éléments, dont le premier s'il vaut "W" indique qu'il y a une "warning".
Ces variables sont manipulées comme des variables C quelconques.
I-3) Connection à ORACLE :
La connection à une base ORACLE se fait par l'ordre SQL :
EXEC SQL CONNECT :username IDENTIFIED BY :password;
Cette demande de connection est bien entendu préalable à toute opération sur la base de données. Il faut noter que username et password sont des variables de communication, de préférence de type VARCHAR.
I-4) Exemple : voir l'exemple I du chapitre V qui permet de faire une simple connection à Oracle
II) Le traitement :
Dans cette partie on peut utiliser les ordres des langages de manipulation et de définition des données, ainsi que des directives SQL spécifiant le traitement d'erreur et la fin de transaction.
II-1) Exemples d'opérations :
"mettre à jour le salaire dans la relation employé"
EXEC SQL update EMP
set sal = :salaire;
"suppression d'un employé"
EXEC SQL DELETE FROM EMP WHERE EMPNO = :empno;
"création d'une nouvelle relation"
EXEC SQL CREATE TABLE EMP_TEST(empno number, ename char(15), job char(10));
II-2) Exécution des SELECT :
1 - l'exécution de la commande retourne un seul n-uplet, on utilise la clause INTO
EXEC SQL select job, sal
into :fonction, :salaire
from EMP
where empno=301;
Exemple : voir l'exemple II du chapitre IV.
2 - l'exécution de la commande retourne un ensemble de n-uplets, on utilise un CURSEUR. Un CURSEUR est une structure de données qui contient l'ensemble des nuplets retournés par le SELECT et qui se manipule comme un fichier séquentiel :
- Association d'un curseur à une commande SQL :
EXEC SQL DECLARE C CURSOR FOR
select job, salaire
from EMP;
- Ouverture du curseur : EXEC SQL OPEN C;
A l'ouverture du curseur, on se trouve sur le premier nuplet sélectionné.
- Fermeture du curseur : EXEC SQL CLOSE C;
- Accès séquentiel aux nuplets du curseur :
L'instruction FETCH permet de lire l'un après l'autre les n-uplets sélectionnés :
EXEC SQL FETCH C INTO :fonction, :salaire;
- Fin de curseur : la fin de curseur est indiquée par la valeur +1403 pour la variable sqlca.sqlcode. Lorsqu'on est en fin de curseur, on ne peut plus manipuler les nuplets, sauf si on effectue une fermeture suivie d'une ouverture (on est de nouveau sur le premier nuplet sélectionné).
Exemples : voir les exemples III et IV du chapitre V.
II-3) Les commandes SQL définies dynamiquement
Il est possible de définir des programmes capables d'accepter et d'exécuter des commandes SQL. Au moment de l'écriture du programme, ces commandes sont inconnues ou incomplètes. Il existe 4 méthodes pour réaliser de tels programmes.
1- pour les commandes SQL (sauf le select) et sans variables, on utilise l'instruction EXECUTE IMMEDIATE
EXEC SQL EXECUTE IMMEDIATE :modif;
/* modif est une chaîne C qui contient un ordre PRO*C */
On retrouve ces instructions dans les exemples 5 et 6 du chapitre V.
2- pour les commandes SQL (sauf le select) et avec variables dont on connaît le nombre et le type, on utilise PREPARE, EXECUTE
EXEC SQL PREPARE S1 FROM :chaîne;
EXEC SQL EXECUTE S1 USING :variable1,:variable2,
...;
On retrouve ces instructions dans l'exemple 7 du chapitre V.
3- pour les commandes SQL dont le nombre et le type des variables est connu, on utilise : PREPARE, DECLARE, OPEN, FETCH
On retrouve ces instructions dans l'exemple 8 du chapitre V.
4- pour l'exécution de select complètement dynamique, on doit déclarer des zones qui vont recevoir les descriptions des champs résultats, des variables paramètres, ....
Voir la documentation Pro*C pour plus de détails.
III - Directives de traitement d'erreur :
ORACLE permet d'utiliser des directives qui spécifient le traitement à effectuer en cas d'erreur :
EXEC SQL WHENEVER [SQLERROR / SQLWARNING / NOT FOUND]
[STOP / CONTINUE / GO TO étiquette];
Ces directives correspondent donc à 3 événements ORACLE :
- SQLERROR : erreur ORACLE (sqlca.sqlcode < 0),
- SQLWARNING : "warning" ORACLE (sqlca.sqlwarn[0]="W")
- NOT FOUND : curseur vide ou fini (sqlca.sqlcode=1403)
Les actions possibles sont :
- STOP : le programme se termine et la transaction est abortée,
- CONTINUE : le programme continue en séquence,
- GO TO : le programme se branche à l'adresse indiquée.
La portée d'une directive WHENEVER va jusqu'à la directive WHENEVER suivante (ou la fin de programme) dans l'ordre du texte source PRO*C (et non pas dans l'ordre d'exécution).
L'erreur classique dans la manipulation des SQL WHENEVER est la suivante :
routine a
{ ...
EXEC SQL WHENEVER ERROR GOTO toto;
...
toto : ...
}
routine b
{ ...
EXEC SQL INSERT ...
} /* donc rien est dit dans b pour SQL WHENEVER */
Par conséquent, au sein de la routine b, on garde les dernières directives rencontrées, donc celles de la routine a. Or l'étiquette toto est locale à a et donc inconnue dans b.
Solutions :
- par exemple avoir systématiquement des étiquettes globales
- définir localement dans chaque routine les directives d'erreurs.
On retrouve ces instructions dans les différents exemples du chapitre V.
IV - Gestion des transactions :
Une transaction est assimilée à une exécution d'un programme. Le début de transaction est implicite (c'est le début de programme), et la fin est soit implicite (erreur non récupérée par un WHENEVER : annulation, ou fin de programme : validation), soit explicite. Les ordres de fin de transaction explicites sont :
EXEC SQL COMMIT WORK [RELEASE];
/* valide les mises à jour. L'option RELEASE désalloue toutes les ressources ORACLE et réalise la déconnection de la base */
EXEC SQL ROLLBACK WORK [RELEASE];
/* annule les mises à jour */
Pour éviter les problèmes de conflit entre le ROLLBACK et les directives WHENEVER, il est prudent d'utiliser le ROLLBACK comme suit :
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL WHENEVER SQLWARNING CONTINUE;
EXEC SQL ROLLBACK WORK;
On retrouve ces instructions dans les différents exemples du chapitre V.
V) Exemples :
Exemple I :
Ce programme permet de faire une simple connection à Oracle
______________________________________________________
# include <stdio.h>
/* Connection a Oracle, avec message d'erreur si un probleme apparait */
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR username[20];
VARCHAR password[20];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE sqlca.h;
main()
{
strcpy(username.arr,"login_oracle"); /* Copie du username*/
username.len = strlen(username.arr);
strcpy(password.arr,"motdepasse_oracle");
/* Copie du mot de passe */
password.len = strlen(password.arr);
EXEC SQL WHENEVER SQLERROR GOTO errexit;
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("\nConnection sur ORACLE de l'usager : %s \n",\
username.arr);
EXEC SQL COMMIT WORK RELEASE;
printf("\nFin de connection sur Oracle. \n");
return(1);
errexit:
printf("\n% .70s \n",sqlca.sqlerrm.sqlerrmc);
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK WORK RELEASE;
printf("\nProblem de connection pour l'usager : %s \n",\
username.arr);
return(0);
}
______________________________________________________
Exemple II :
______________________________________________________
# include <stdio.h>
/* Connection a Oracle,
demande a l'utilisateur le numero d'un employe,
interroge la BD sur le nom, le departement, le salaire et
la commission de l'employe,
et enfin affiche le resultat
avec message d'erreur si un probleme apparait */
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR username[20];
VARCHAR password[20];
int emp_number;
VARCHAR emp_name[15];
float salary;
float commission;
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE sqlca.h;
main()
{
/* CONNECTION A ORACLE */
strcpy(username.arr,"login_oracle"); /* Copie du username*/
username.len = strlen(username.arr);
strcpy(password.arr,"motdepasse_oracle");
/* Copie du mot de passe */
password.len = strlen(password.arr);
EXEC SQL WHENEVER SQLERROR GOTO errexit;
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("\nConnection sur ORACLE de l'usager : %s \n",\
username.arr);
/* DEMANDE DU NUMERO DE L'EMPLOYE */
printf("\n\nDonner le numero de l'employe :");
scanf("%d", &emp_number);
/* INTERROGATION D'ORACLE */
EXEC SQL SELECT ENAME, SAL, COMM
INTO :emp_name, :salary, :commission
FROM EMP
WHERE EMPNO = :emp_number;
/* Il faut toujours terminer les chaines de caracteres par \0 */
emp_name.arr[emp_name.len] = '\0';
/* IMPRESSION DU RESULTAT */
printf("\n\nEmploye\tSalaire\tCommission\n");
printf("-------\t-------\t----------\n");
printf("%-s\t%6.2f\t%6.2f\n",emp_name.arr,salary,commission);
EXEC SQL COMMIT WORK RELEASE;
printf("\nFin de connection sur Oracle. \n");
return(1);
errexit:
printf("\n% .70s \n",sqlca.sqlerrm.sqlerrmc);
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK WORK RELEASE;
return(0);
}
______________________________________________________
Exemple III :
______________________________________________________
# include <stdio.h>
/* Connection a Oracle,
interroge la BD sur la liste des employes dont le
job est SALESMAN
affiche le resultat
avec message d'erreur si un probleme apparait */
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR username[20];
VARCHAR password[20];
int emp_number;
VARCHAR emp_name[15];
float salary;
float commission;
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE sqlca.h;
main()
{
/* CONNECTION A ORACLE */
strcpy(username.arr,"login_oracle"); /* Copie du username*/
username.len = strlen(username.arr);
strcpy(password.arr,"motdepasse_oracle");
/* Copie du mot de passe */
password.len = strlen(password.arr);
EXEC SQL WHENEVER SQLERROR GOTO errexit;
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("\nConnection sur ORACLE de l'usager : %s \n",\
username.arr);
/* INTERROGATION D'ORACLE */
EXEC SQL DECLARE salesmen CURSOR FOR
SELECT ENAME, SAL, COMM
FROM EMP
WHERE JOB='SALESMAN';
/* TRAITEMENT DE salesmen */
EXEC SQL OPEN salesmen;
/* PAS DE RESULTAT */
EXEC SQL WHENEVER NOT FOUND GOTO fin_de_reponse;
/* IMPRESSION DU RESULTAT */
printf("\n\n LISTE DES SALESMEN ");
printf("\nEmploye \tSalaire \tCommission\n");
printf("------- \t---------- \t----------\n");
for ( ; ; )
{
EXEC SQL FETCH salesmen INTO :emp_name, :salary, :commission;
/* il faut toujours terminer les chaines par \0 */
emp_name.arr[emp_name.len]='\0';
printf("%-s\t\t%8.2f\t%8.2f\n",emp_name.arr,salary,commission);
}
fin_de_reponse :
EXEC SQL CLOSE salesmen;
EXEC SQL COMMIT WORK RELEASE;
printf("\nFin de connection sur Oracle. \n");
return(1);
errexit:
printf("\n% .70s \n",sqlca.sqlerrm.sqlerrmc);
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK WORK RELEASE;
return(0);
}
______________________________________________________
Exemple IV :
______________________________________________________
# include <stdio.h>
/* Connection a Oracle,
interroge la BD sur la liste des employes
en demandant leur numero, leur nom et leur salaire
Ces triplets sont recuperes et affiches par paquets de 5,
message d'erreur en cas de probleme */
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR username[20];
VARCHAR password[20];
int emp_number[5];
VARCHAR emp_name[5][15];
float salary[5];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE sqlca.h;
void afficher_nuplets(); /* defini apres le programme principal */
main()
{
int nb_nuplets; /* nb de nuplets manipules */
/* CONNECTION A ORACLE */
strcpy(username.arr,"login_oracle"); /* Copie du username*/
username.len = strlen(username.arr);
strcpy(password.arr,"motdepasse_oracle");
/* Copie du mot de passe */
password.len = strlen(password.arr);
EXEC SQL WHENEVER SQLERROR GOTO errexit;
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("\nConnection sur ORACLE de l'usager : %s \n",\
username.arr);
/* INTERROGATION D'ORACLE */
EXEC SQL DECLARE triplet CURSOR FOR
SELECT EMPNO, ENAME, SAL
FROM EMP;
/* TRAITEMENT DE triplet */
EXEC SQL OPEN triplet;
/* PAS DE RESULTAT */
EXEC SQL WHENEVER NOT FOUND GOTO fin_de_reponse;
/* TRAITEMENT DES RESULTATS */
nb_nuplets = 0;
while(1)
{
/* les triplets sont recuperes et affiches
par paquets de 5 */
EXEC SQL FETCH triplet INTO :emp_number, :emp_name, :salary;
/* sqlca.errd[2] donne le nombre de triplets manipules ,
sqlca.errd[2] est incremente apres chaque FETCH */
afficher_nuplets(sqlca.sqlerrd[2] - nb_nuplets);
nb_nuplets = sqlca.sqlerrd[2];
}
fin_de_reponse :
if ((sqlca.sqlerrd[2] - nb_nuplets) > 0)
afficher_nuplets(sqlca.sqlerrd[2] - nb_nuplets);
EXEC SQL CLOSE triplet;
EXEC SQL COMMIT WORK RELEASE;
printf("\nFin de connection sur Oracle. \n");
return(1);
errexit:
printf("\n% .70s \n",sqlca.sqlerrm.sqlerrmc);
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK WORK RELEASE;
return(0);
}
void afficher_nuplets(n)
{
int i;
/* IMPRESSION DU RESULTAT */
printf("\nNumero \tNom \tSalaire\n");
printf("------ \t--- \t-------\n");
for (i=0 ;i<n ;i++ )
{
/* il faut toujours terminer les chaines par \0 */
emp_name[i].arr[emp_name[i].len]='\0';
printf("%-15d\t%-13s\t%6.2f\n",emp_number[i],emp_name[i].arr,salary[i]) ;
}
}
______________________________________________________
Exemple V :
______________________________________________________
# include <stdio.h>
/* Connection a Oracle,
avec message d'erreur si un probleme apparait
1) Destruction de la table EMP - si elle existait auparavant
2) Creation de la table EMP a partir de la table EMP accessible par synonyme
3) Mise a jour de la table EMP : on met a 100 les commissions nulles
les points 1, 2 et 3 ne fonctionnent pas au sein du meme programme
les points 1 et 2 doivent être mis dans un fichier
le point 3 doit être mis dans un autre fichier */
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR username[20];
VARCHAR password[20];
char requete[132];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE sqlca.h;
main()
{
strcpy(username.arr,"login_oracle"); /* Copie du username*/
username.len = strlen(username.arr);
strcpy(password.arr,"motdepasse_oracle");
/* Copie du mot de passe */
password.len = strlen(password.arr);
EXEC SQL WHENEVER SQLERROR GOTO errexit;
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("\nConnection sur ORACLE de l'usager : %s \n", \
username.arr);
strcpy(requete,"DROP TABLE EMP");
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL EXECUTE IMMEDIATE :requete;
printf("La table EMP est detruite. \n");
EXEC SQL WHENEVER SQLERROR GOTO errexit;
strcpy(requete,"CREATE TABLE EMP AS SELECT EMPNO, ENAME, JOB, SAL, COMM FROM EMP");
EXEC SQL EXECUTE IMMEDIATE :requete;
printf("La table EMP est creee. \n");
EXEC SQL COMMIT WORK;
printf("La transaction est validee. \n");
strcpy(requete,"UPDATE EMP SET COMM=100 WHERE COMM IS NULL");
EXEC SQL EXECUTE IMMEDIATE :requete;
printf("La mise a jour est faite, %d nuplets modifies. \n", sqlca.sqlerrd[2]);
EXEC SQL COMMIT WORK RELEASE;
printf("\nFin de connection sur Oracle. \n");
return(1);
errexit:
printf("\n% .70s \n",sqlca.sqlerrm.sqlerrmc);
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK WORK RELEASE;
printf("\nProblem de connection pour l'usager : %s \n", username.arr);
return(0);
}
Exemple VI :
______________________________________________________
# include <stdio.h>
/* Connection a Oracle,
avec message d'erreur si un probleme apparait
On suppose pour executer ce programme que la relation EMP existe, et que l'on peut la modifier. On met a 100 la commission de certains employes. La condition (clause where) est fournie par l'utilisateur */
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR username[20];
VARCHAR password[20];
char requete[132];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE sqlca.h;
main()
{
char clausewhere[80];
strcpy(username.arr,"login_oracle"); /* Copie du username*/
username.len = strlen(username.arr);
strcpy(password.arr,"motdepasse_oracle");
/* Copie du mot de passe */
password.len = strlen(password.arr);
EXEC SQL WHENEVER SQLERROR GOTO errexit;
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("\nConnection sur ORACLE de l'usager : %s \n", \
username.arr);
strcpy(requete,"UPDATE EMP SET COMM = 100 WHERE ");
printf("Completez la requete %s ", requete);
asks("", clausewhere);
strcat(requete, clausewhere);
EXEC SQL EXECUTE IMMEDIATE :requete);
printf("%s executee. \n %d nuplets modifies. \n",requete,sqlca.sqlerrd[2]);
EXEC SQL COMMIT WORK RELEASE;
printf("\nFin de connection sur Oracle. \n");
return(1);
errexit:
printf("\n% .70s \n",sqlca.sqlerrm.sqlerrmc);
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK WORK RELEASE;
printf("\nProblem de connection pour l'usager : %s \n", username.arr);
return(0);
}
/* askn(text,variable)
print the 'text' on STDOUT and read an integer variable from
SDTIN.
text points to the null terminated string to be printed
variable points to an integer variable
askn returns a 1 if the variable was read successfully or a
-1 if -eof- was encountered
*/
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);
}
/* asks(text,variable)
print the 'text' on STDOUT and read up to 'len' characters into
the buffer pointed to by variable from STDIN.
text points to the null terminated string to be printed
variable points to a buffer of at least 'len'+1 characters
asks returns the number of character read into the string, or a
-1 if -eof- was encountered
*/
int asks(text,variable)
char text[],variable[];
{
printf(text);
return( gets(variable) == (char *)0 ? EOF : strlen(variable) );
}
Exemple VII :
______________________________________________________
# include <stdio.h>
/* Connection a Oracle,
avec message d'erreur si un probleme apparait
On suppose pour executer ce programme que la relation EMP existe, et que l'on peut la modifier. On met a jour la commission de certains employes. La condition (clause where) est fournie par l'utilisateur ainsi que la nouvelle valeur de la commission */
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR username[20];
VARCHAR password[20];
char requete[132];
int commission;
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE sqlca.h;
main()
{
char clausewhere[80];
strcpy(username.arr,"login_oracle"); /* Copie du username*/
username.len = strlen(username.arr);
strcpy(password.arr,"motdepasse_oracle");
/* Copie du mot de passe */
password.len = strlen(password.arr);
EXEC SQL WHENEVER SQLERROR GOTO errexit;
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("\nConnection sur ORACLE de l'usager : %s \n", \
username.arr);
strcpy(requete,"UPDATE EMP SET COMM = :commission WHERE ");
printf("Completez la requete %s ", requete);
asks("", clausewhere);
strcat(requete, clausewhere);
EXEC SQL PREPARE S1 FROM :requete;
askn("Donnez la nouvelle valeur de la commission :",&commission);
EXEC SQL EXECUTE S1 USING :commission;
printf("%s executee. \nNouvelle commission :%d\n %d nuplets modifies. \n",requete,commission,sqlca.sqlerrd[2]);
EXEC SQL COMMIT WORK RELEASE;
printf("\nFin de connection sur Oracle. \n");
return(1);
errexit:
printf("\n% .70s \n",sqlca.sqlerrm.sqlerrmc);
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK WORK RELEASE;
printf("\nProblem de connection pour l'usager : %s \n", username.arr);
return(0);
}
Exemple VIII :
______________________________________________________
# include <stdio.h>
/* Connection a Oracle,
avec message d'erreur si un probleme apparait
On suppose pour executer ce programme que la relation EMP existe, et que l'on peut la lire. On liste le contenu de la relation EMP
La condition (clause where) est fournie par l'utilisateur */
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR username[20];
VARCHAR password[20];
char requete[132];
int deptno;
char nom[10];
float salaire;
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE sqlca.h;
main()
{
char clausewhere[80];
int i;
strcpy(username.arr,"login_oracle"); /* Copie du username*/
username.len = strlen(username.arr);
strcpy(password.arr,"motdepasse_oracle");
/* Copie du mot de passe */
password.len = strlen(password.arr);
EXEC SQL WHENEVER SQLERROR GOTO errexit;
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("\nConnection sur ORACLE de l'usager : %s \n", username.arr);
strcpy(requete,"SELECT ENAME, SAL FROM EMP ");
printf("Completez la requete %s ", requete);
asks("", clausewhere);
strcat(requete, clausewhere);
EXEC SQL PREPARE S1 FROM :requete;
EXEC SQL DECLARE C1 CURSOR FOR S1;
EXEC SQL OPEN C1;
printf("Employe \tSalaire \n");
printf("----------\t----------\n");
EXEC SQL WHENEVER NOT FOUND GOTO finboucle;
for (i=0;;i++)
{ EXEC SQL FETCH C1 INTO :nom, :salaire);
printf("%-10s\t%6.2f\n",nom,salaire);
}
finboucle:
printf("\n\n%d nuplets selectionnes.\n",i);
EXEC SQL COMMIT WORK RELEASE;
printf("\nFin de connection sur Oracle. \n");
return(1);
errexit:
printf("\n% .70s \n",sqlca.sqlerrm.sqlerrmc);
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK WORK RELEASE;
printf("\nProblem de connection pour l'usager : %s \n", username.arr);
return(0);
}