You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

789 lines
21 KiB

/*
* Pro*C
* TP6 - Exercice 1
*
* Auteur : Damien NGUYEN
* Groupe : 3
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
EXEC SQL INCLUDE SQLCA.H;
EXEC SQL INCLUDE SQLDA.H;
EXEC SQL INCLUDE ORACA.H;
#define CLEAR system("clear")
/********** Constantes **********/
#define SQL_COMMIT 1
#define STOP 1
#define CONTINUE 0
#define SQL_ROLLBACK 0
#define SQL_SUCCESS 0
#define NOT_FOUND 1403
/********** Liste des fonctions **********/
void connexion(void);
void erreur_sql(int arret);
void deconnexion(int validation);
void enregistrer(void);
void modifier(void);
void supprimer(void);
void toutAfficher(void);
void afficherLocataires(void);
void afficherEnCours(void);
void enregistrerBidon(void);
void modifierTousLesNumerosDepartement(void);
void afficherCertainNombreDImmeubles(void);
void mettreFinLocationNULL(void);
void selectSansINTO(void);
void afficherPaquetsDeCinq (void);
/*
* Fonction de connexion à Oracle.
*
* Les identifiants sont rentrés en dur pour ne pas avoir à les retaper
* à la main à chaque test, mais dans l'idéal, on demande à l'utilisateur
* de les rentrer et on concatène les identifiants à uid.arr.
*/
void connexion(void) {
VARCHAR uid[50];
char identifiants[30] = "danguyen1/danguyen1@kirov";
printf("Connexion avec les identifiants suivants : %s .\n", identifiants);
strcpy(uid.arr, identifiants);
uid.len = strlen(uid.arr);
EXEC SQL CONNECT :uid;
if (sqlca.sqlcode == SQL_SUCCESS) {
printf("Connexion réussie avec succès !\n\n");
}
else {
printf("Connexion échouée !\n\n");
exit(EXIT_FAILURE);
}
}
/*
* Fonction qui affiche les code et message d'erreur SQL.
*
* Paramètres :
* arret STOP(1) pour quitter, n'importe quoi pour continuer
*/
void erreur_sql(int arret) {
printf("Code d'erreur : %d.\n", sqlca.sqlcode);
printf("Message erreur : %.*s.\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
if (arret == STOP) {
deconnexion(SQL_ROLLBACK);
exit(EXIT_FAILURE);
}
}
/*
* Fonction de déconnexion.
*
* Paramètres :
* validation SQL_COMMIT(1) pour COMMIT, n'importe quoi pour ROLLBACK
*/
void deconnexion(int validation) {
if (validation == SQL_COMMIT) {
EXEC SQL COMMIT WORK RELEASE;
}
else {
EXEC SQL ROLLBACK WORK RELEASE;
}
printf("Déconnexion réussie, travail %s.\n", validation == SQL_COMMIT ? "enregistré" : "annulé");
}
/*
* Fonction d'enregistrement d'un nouvel immeuble.
*/
void enregistrer(void) {
char deptimm[3], noimm[5];
VARCHAR adrimm[81];
printf("Saisir le numéro d'immeuble : ");
scanf("%s%*c", noimm);
printf("Saisir la nouvelle adresse de l'immeuble : ");
fgets(adrimm.arr, sizeof (adrimm.arr), stdin);
if (adrimm.arr[strlen(adrimm.arr) - 1] == '\n') {
adrimm.arr[strlen(adrimm.arr) - 1] = '\0';
}
adrimm.len = strlen(adrimm.arr);
printf("Saisir le nouveau numéro de département : ");
scanf("%s%*c", deptimm);
EXEC SQL
INSERT INTO TIMM2018
VALUES(:noimm, :adrimm, :deptimm);
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
EXEC SQL COMMIT;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
printf("Enregistré avec succès.\n");
}
/*
* Fonction de modification d'un immeuble existant.
* Techniquement, il est uniquement possible de changer l'adresse
* et le département.
*/
void modifier(void) {
char deptimm[3], noimm[5];
VARCHAR adrimm[80];
printf("Saisir le numéro d'immeuble : ");
scanf("%s%*c", noimm);
printf("Saisir la nouvelle adresse de l'immeuble : ");
fgets(adrimm.arr, sizeof (adrimm.arr), stdin);
if (adrimm.arr[strlen(adrimm.arr) - 1] == '\n') {
adrimm.arr[strlen(adrimm.arr) - 1] = '\0';
}
adrimm.len = strlen(adrimm.arr);
printf("Saisir le nouveau numéro de département : ");
scanf("%s%*c", deptimm);
EXEC SQL
UPDATE TIMM2018
SET ADRIMM = :adrimm, DEPTIMM = :deptimm
WHERE NOIMM = :noimm;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
EXEC SQL COMMIT;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
printf("Modifié avec succès.\n");
}
/*
* Fonction de suppression d'un immeuble existant.
* On supprime toutes les clés étrangères des autres tables avant.
*/
void supprimer(void) {
char noimm[5];
printf("Saisir le numéro d'immeuble : ");
scanf("%s%*c", noimm);
EXEC SQL
DELETE FROM TLOCATION2018
WHERE REFLOG IN (
SELECT REFLOG
FROM TLOGT2018
WHERE NOIMM = :noimm
);
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
EXEC SQL
DELETE FROM TLOGT2018
WHERE NOIMM = :noimm;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
EXEC SQL
DELETE FROM TIMM2018
WHERE NOIMM = :noimm;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
EXEC SQL COMMIT;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
printf("Supprimé avec succès.\n");
}
/*
* Fonction qui affiche tous les logemens gérés par l'agence.
*/
void toutAfficher(void) {
char deptimm[5], reflog[5];
int cpt = 1, superf;
float loyer;
VARCHAR adrimm[81];
EXEC SQL
DECLARE clog CURSOR FOR
SELECT DEPTIMM, ADRIMM, REFLOG, SUPERF, LOYER
FROM TIMM2018 i, TLOGT2018 l
WHERE i.NOIMM = l.NOIMM
ORDER BY DEPTIMM, ADRIMM ASC;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
EXEC SQL
OPEN clog;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
EXEC SQL
FETCH clog INTO :deptimm, :adrimm, :reflog, :superf, :loyer;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
if (sqlca.sqlcode == NOT_FOUND) {
printf("Aucun logement trouvé !\n");
}
while (sqlca.sqlcode != NOT_FOUND) {
printf("----- Logement %d -----\n", cpt);
printf("Département : %s\n", deptimm);
printf("Adresse : %.*s\n", adrimm.len, adrimm.arr);
printf("Référence logement : %s\n", reflog);
printf("Superficie : %d\n", superf);
printf("Loyer : %.2f euros/mois\n\n", loyer);
EXEC SQL
FETCH clog INTO :deptimm, :adrimm, :reflog, :superf, :loyer;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
++cpt;
}
EXEC SQL CLOSE clog;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
}
/*
* Fonction qui affiche les clients louant ou ayant loué un logement saisi.
*/
void afficherLocataires(void) {
char reflog[5], nocli[20][7], finloc[20][11];
int i;
short indicateur[20];
VARCHAR nomcli[20][21];
printf("Saisir le numéro de logement voulu : ");
scanf("%s%*c", reflog);
EXEC SQL
SELECT NOCLI, NOMCLI, FINLOC
INTO :nocli, :nomcli, :finloc:indicateur
FROM TLOCATION2018 l, TCLIENT2018 c
WHERE REFLOG = :reflog
AND l.NOLOC = c.NOCLI;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
if (sqlca.sqlerrd[2] > 0) {
for (i = 0; i < sqlca.sqlerrd[2]; ++i) {
printf("Logement %s:\t%.*s(%s)\t=>\t%s\n", reflog, nomcli[i].len, nomcli[i].arr, nocli[i], indicateur[i] == -1 ? "occupé" : "libre");
}
}
else {
printf("Aucun locataire ou ancien locataire.\n");
}
}
/*
* Focntion qui affiche les logements en cours.
*/
void afficherEnCours(void) {
char deptimm[3], noprop[7], noloc[7];
int cpt = 1;
VARCHAR adrimm[81], nomprop[21], nomloc[21];
EXEC SQL
DECLARE cloc CURSOR FOR
SELECT ADRIMM, DEPTIMM, NOPROP, NOLOC
FROM TIMM2018 i, TLOGT2018 l
WHERE NOLOC IS NOT NULL
AND i.NOIMM = l.NOIMM;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
EXEC SQL
OPEN cloc;
EXEC SQL FETCH cloc INTO :adrimm, :deptimm, :noprop, :noloc;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
if (sqlca.sqlcode == NOT_FOUND) {
printf("Aucun logement trouvé !\n");
}
while (sqlca.sqlcode != NOT_FOUND) {
EXEC SQL
SELECT NOMCLI
INTO :nomprop
FROM TCLIENT2018
WHERE NOCLI = :noprop;
EXEC SQL
SELECT NOMCLI
INTO :nomloc
FROM TCLIENT2018
WHERE NOCLI = :noloc;
printf("----- Logement %d -----\n", cpt);
printf("Propriétaire : %.*s\n", nomprop.len, nomprop.arr);
printf("Locataire : %.*s\n", nomprop.len, nomprop.arr);
printf("Adresse : %.*s (%s)\n", adrimm.len, adrimm.arr, deptimm);
EXEC SQL FETCH cloc INTO :adrimm, :deptimm, :noprop, :noloc;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
++cpt;
}
EXEC SQL CLOSE cloc;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
}
/*
* Fonction qui enregistre plein de lignes bidons.
*/
void enregistrerBidon(void) {
char buffer[5], deptimm[3], noimm[5];
int i;
VARCHAR adrimm[81];
strcpy(adrimm.arr, "Adresse bidon");
adrimm.len = strlen(adrimm.arr);
strcpy(deptimm, "12");
for (i = 4; i < 50; ++i) {
if (i < 10) {
strcpy(noimm, "I00");
}
else {
strcpy(noimm, "I0");
}
/* Stocke l'entier dans buffer pour pouvoir le concaténer à noimm. */
snprintf(buffer, sizeof buffer, "%d", i);
strcat(noimm, buffer);
EXEC SQL
INSERT INTO TIMM2018
VALUES(:noimm, :adrimm, :deptimm);
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
EXEC SQL COMMIT;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
printf("I00%d nregistré avec succès.\n", i);
}
}
/*
* Fonction qui modifie la totalité des numéros département à 01.
*/
void modifierTousLesNumerosDepartement(void) {
EXEC SQL BEGIN DECLARE SECTION;
int nbMax;
EXEC SQL END DECLARE SECTION;
nbMax = 9;
EXEC SQL
FOR :nbMax
UPDATE TIMM2018
SET deptimm = '01';
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
printf("%d lignes ont été mises à jour.\n", nbMax);
}
/*
* Fonction qui affiche un certain nombre de lignes avec un curseur.
*/
void afficherCertainNombreDImmeubles(void) {
int i;
EXEC SQL BEGIN DECLARE SECTION;
int nbLignes;
char noimm[10][5], deptimm[10][3];
VARCHAR adrimm[10][81];
EXEC SQL END DECLARE SECTION;
printf("Combien de lignes voulez-vous afficher (1-9) ? ");
scanf("%d%*c", &nbLignes);
EXEC SQL
DECLARE cursor_imm CURSOR FOR
SELECT noimm, adrimm, deptimm
FROM TIMM2018
ORDER BY NOIMM ASC;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
EXEC SQL OPEN cursor_imm;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
EXEC SQL FOR :nbLignes
FETCH cursor_imm INTO :noimm, :adrimm, :deptimm;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
printf("Liste des %d premiers immeubles:\n", nbLignes);
for (i = 0; i < nbLignes; ++i) {
printf("\t%s : %.*s (%s)\n", noimm[i], adrimm[i].len, adrimm[i].arr, deptimm[i]);
}
EXEC SQL CLOSE cursor_imm;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
}
/*
* Fonction qui met la fin de location à NULL pour une location
* saisie.
*/
void mettreFinLocationNULL(void) {
int i;
char reflog[5], finloc[11];
short indicateur, newIndicateur = -1;
printf("Saisir la référence logement : ");
scanf("%s%*c", reflog);
EXEC SQL
UPDATE TLOCATION2018
SET finloc = :finloc INDICATOR :newIndicateur // mot clé INDICATOR pas obligatoire
WHERE reflog = :reflog;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
EXEC SQL COMMIT;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
printf("La ligne a été modifiée.\n");
}
/*
* Fonction qui permet de voir que SELECT sans INTO compile, n'affiche
* rien, et donc ne sert pas à grand chose.
*/
void selectSansINTO(void) {
EXEC SQL
SELECT COUNT(*) FROM TLOCATION2018;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
printf("Succès !\n");
}
/*
* Affiche les immeubles par paquets de 5 à chaque fois qu'on appuie sur
* entrée.
*/
void afficherPaquetsDeCinq (void) {
int i;
EXEC SQL BEGIN DECLARE SECTION;
int nbLignes = 50;
char noimm[50][5], deptimm[50][3];
VARCHAR adrimm[50][81];
EXEC SQL END DECLARE SECTION;
EXEC SQL
DECLARE c_imm CURSOR FOR
SELECT noimm, adrimm, deptimm
FROM TIMM2018
ORDER BY NOIMM ASC;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
EXEC SQL OPEN c_imm;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
nbLignes = 50;
EXEC SQL FOR :nbLignes
FETCH c_imm INTO :noimm, :adrimm, :deptimm;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
for (i = 1; i < nbLignes; ++i) {
printf("\t%s : %.*s (%s)\n", noimm[i], adrimm[i].len, adrimm[i].arr, deptimm[i]);
if ((i % 5) == 0) {
printf("\nEntrée pour les 5 prochains.\n");
scanf("%*c");
}
}
EXEC SQL CLOSE c_imm;
if (sqlca.sqlcode < SQL_SUCCESS) {
erreur_sql(STOP);
}
}
/*
* Affiche un menu avec différents choix possibles.
*
* Retourne :
* le choix qui va être utilisé dans le switch du main
*/
int menu(void) {
int choix;
printf("Vous voulez :\n");
printf("\t1 - saisir un nouvel immeuble ?\n");
printf("\t2 - modifier un immeuble existant ?\n");
printf("\t3 - supprimer un immeuble existant ?\n");
printf("\t4 - afficher tous les logements ?\n");
printf("\t5 - affichier les disponibilités selon le logement\n");
printf("\t6 - afficher les logements en cours de location\n");
printf("\t7 - enregistrer des immeubles bidons\n");
printf("\t8 - mettre tous les numéros département à une valeur donnée\n");
printf("\t9 - afficher un certain nombre d'immeubles avec un curseur\n");
printf("\t10 - mettre une fin de location à NULL\n");
printf("\t11 - tester le SELECT sans INTO qui n'affiche rien\n");
printf("\t12 - afficher les immeubles par paquets de 5\n");
printf("Choix : ");
scanf("%d%*c", &choix);
return choix;
}
/*
* Fonction principale.
*
* Paramètres :
* argc Le nombre d'arguments
* argv Le tableau d'arguments
*
* Retourne :
* le code de retour défini dans stdlib.h
* (EXIT_SUCCESS = 0)
*/
int main(int argc, char const *argv[]) {
int choix, validation;
CLEAR;
connexion();
choix = menu();
do {
switch (choix) {
case 1:
enregistrer();
break;
case 2:
modifier();
break;
case 3:
supprimer();
break;
case 4:
toutAfficher();
break;
case 5:
afficherLocataires();
break;
case 6:
afficherEnCours();
break;
case 7:
enregistrerBidon();
break;
case 8:
modifierTousLesNumerosDepartement();
break;
case 9:
afficherCertainNombreDImmeubles();
break;
case 10:
mettreFinLocationNULL();
break;
case 11:
selectSansINTO();
break;
case 12:
afficherPaquetsDeCinq();
break;
default:
printf("Le choix est incorrect, recommencez : ");
scanf("%d%*c", &choix);
CLEAR;
break;
}
} while (choix < 1 || choix > 12);
printf("Enregistrer le travail ? (1 = oui, * = non)\n");
scanf("%d%*c", &validation);
deconnexion(validation);
return EXIT_SUCCESS;
}
/****************************************************************************************************
Cas où on affiche tout
****************************************************************************************************
danguyen1@iutclinfa1910:~/S2/Database/pr4$ ./ex4
Connexion avec les identifiants suivants : danguyen1/danguyen1@kirov .
Connexion réussie avec succès !
Vous voulez :
1 - saisir un nouvel immeuble ?
2 - modifier un immeuble existant ?
3 - supprimer un immeuble existant ?
4 - afficher tous les logements ?
5 - affichier les disponibilités selon le logement
6 - afficher les logements en cours de location
Choix : 4
----- Logement 1 -----
Département : 03
Adresse : Bd de Courtais Montlucon
Référence logement : L003
Superficie : 60
Loyer : 320.00 euros/mois
----- Logement 2 -----
Département : 63
Adresse : Bd Lafayette Clermont Fd
Référence logement : L002
Superficie : 60
Loyer : 400.00 euros/mois
----- Logement 3 -----
Département : 63
Adresse : Bd Lafayette Clermont Fd
Référence logement : L005
Superficie : 90
Loyer : 470.00 euros/mois
----- Logement 4 -----
Département : 63
Adresse : Bd Lafayette Clermont Fd
Référence logement : L004
Superficie : 100
Loyer : 700.00 euros/mois
----- Logement 5 -----
Département : 63
Adresse : Bd Lafayette Clermont Fd
Référence logement : L001
Superficie : 90
Loyer : 450.00 euros/mois
Enregistrer le travail ? (1 = oui, * = non)
2
Déconnexion réussie, travail annulé.
****************************************************************************************************/
/****************************************************************************************************
Cas où on affiche les disponibilités selon le logement saisi
****************************************************************************************************
danguyen1@iutclinfa1910:~/S2/Database/pr4$ ./ex4
Connexion avec les identifiants suivants : danguyen1/danguyen1@kirov .
Connexion réussie avec succès !
Vous voulez :
1 - saisir un nouvel immeuble ?
2 - modifier un immeuble existant ?
3 - supprimer un immeuble existant ?
4 - afficher tous les logements ?
5 - affichier les disponibilités selon le logement
6 - afficher les logements en cours de location
Choix : 5
Saisir le numéro de logement voulu : L002
Logement L002: Martin(CL0002) => libre
Logement L002: Durand(CL0004) => libre
Logement L002: Martin(CL0002) => libre
Logement L002: Martin(CL0002) => occupé
Enregistrer le travail ? (1 = oui, * = non)
2
Déconnexion réussie, travail annulé.
****************************************************************************************************/
/****************************************************************************************************
Cas où on affiche les disponibilités selon le logement saisi et où il n'y a pas de locataire
****************************************************************************************************
danguyen1@iutclinfa1910:~/S2/Database/pr4$ ./ex4
Connexion avec les identifiants suivants : danguyen1/danguyen1@kirov .
Connexion réussie avec succès !
Vous voulez :
1 - saisir un nouvel immeuble ?
2 - modifier un immeuble existant ?
3 - supprimer un immeuble existant ?
4 - afficher tous les logements ?
5 - affichier les disponibilités selon le logement
6 - afficher les logements en cours de location
Choix : 5
Saisir le numéro de logement voulu : L001
Aucun locataire ou ancien locataire.
Enregistrer le travail ? (1 = oui, * = non)
2
Déconnexion réussie, travail annulé.
****************************************************************************************************/
/****************************************************************************************************
Cas où on affiche l'ensemble des locations en cours
****************************************************************************************************
danguyen1@iutclinfa1910:~/S2/Database/pr4$ ./ex4
Connexion avec les identifiants suivants : danguyen1/danguyen1@kirov .
Connexion réussie avec succès !
Vous voulez :
1 - saisir un nouvel immeuble ?
2 - modifier un immeuble existant ?
3 - supprimer un immeuble existant ?
4 - afficher tous les logements ?
5 - affichier les disponibilités selon le logement
6 - afficher les logements en cours de location
Choix : 6
----- Logement 1 -----
Propriétaire : Dupond
Locataire : Dupond
Adresse : Bd Lafayette Clermont Fd (63)
----- Logement 2 -----
Propriétaire : Thibaut
Locataire : Thibaut
Adresse : Bd de Courtais Montlucon (03)
----- Logement 3 -----
Propriétaire : Thibaut
Locataire : Thibaut
Adresse : Bd Lafayette Clermont Fd (63)
Enregistrer le travail ? (1 = oui, * = non)
2
Déconnexion réussie, travail annulé.
****************************************************************************************************/