/* * Pro*C * TP6 - Exercice 1 * * Auteur : Damien NGUYEN * Groupe : 3 */ #include #include #include 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é. ****************************************************************************************************/