Embedded SQL Pro*C : du SQL dans du C pour Oracle

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

}