Baze podataka 1/Lab 1 januar 2021

Izvor: SI Wiki
< Базе података 1
Datum izmene: 4. februar 2021. u 20:30; autor: TopOfKeks (razgovor | doprinosi) (Нова страница: {{tocright}} == Поставка == Банка путем својих филијала (прати се назив и адреса) у разним местима (п…)
(razl) ← Starija izmena | Trenutna verzija (razl) | Novija izmena → (razl)
Pređi na navigaciju Pređi na pretragu

Postavka

Banka putem svojih filijala (prati se naziv i adresa) u raznim mestima (prate se poštanski broj i naziv) opslužuje svoje komitente (prati se naziv i adresa) koji mogu biti bez mesta, a u trenutku prvog pojavljivanja u banci prijavljuju sedište u određenom mestu.

Svaki komitent može da ima više računa u svakoj od filijala (prate se status, broj stavki, dozvoljeni minus, i stanje), a mora imati bar jedan račun. Status računa može biti aktivan, blokiran ili ugašen. Račun postaje blokiran kada pređe u nedozvoljeni minus, a aktivira se kada stanje pređe u dozvoljeni minus.

Komitenti sa svojih računa vrše transakcije putem stavki prometa (prate se redni broj, datum i vreme) koje mogu biti uplate (prati se osnov i iznos) ili isplate (prate se iznos i provizija), pri čemu je to moguće u bilo kojoj filijali.

Zadatak

Napisati program koji vrši uplatu za zadati račun. Funkcija kao argumente prima idFil, idRac i iznos. Treba da se obavesti korisnik ukoliko je račun nakon uplate promenio status, kao i da li je uplata bila uspešna. Funkcija je potrebno da bude otporna na greške.

Rešenje

Za rešavanje je potrebna Banka.db baza sa stranice predmeta i SQLite C biblioteka za komunikaciju s bazom. Oba su već data na laboratorijskoj vežbi.

#include <iostream>
#include <string>
#include "sqlite3.h"

sqlite3 *otvoriBazu(const char *imeBaze) {
    sqlite3 *baza = nullptr;
    int kod = sqlite3_open(imeBaze, &baza);
    if (kod != SQLITE_OK) {
        throw std::string("Kod pri otvaranju: ") + std::to_string(kod);
    }
    return baza;
}

void zatvoriBazu(sqlite3 *baza) {
    int kod = sqlite3_close(baza);
    if (kod != SQLITE_OK) {
        throw std::string("Kod pri zatvaranju: ") + std::to_string(kod);
    }
}

void pripremi(sqlite3 *baza, const char *sql, sqlite3_stmt *&stmt) {
    int kod = sqlite3_prepare(baza, sql, -1, &stmt, nullptr);
    if (kod != SQLITE_OK) {
        std::string greska = std::string("Greška pri pripremanju upita: ") + sqlite3_errmsg(baza);
        sqlite3_finalize(stmt);
        throw greska;
    }
}

void izvrsiBezParametara(sqlite3 *baza, const char *sql, int (*callback)(void *, int, char **, char **) = nullptr) {
    char *errmsg = nullptr;
    int kod = sqlite3_exec(baza, sql, callback, nullptr, &errmsg);
    if (kod != SQLITE_OK) {
        std::string greska = std::string("Greška pri izvršavanju: ") + errmsg;
        sqlite3_free(errmsg);
        throw greska;
    }
}

void proknjiziUplatu(sqlite3 *baza) {
    const char *sql = "INSERT INTO Uplata (IdSta, Osnov) VALUES (?, 'Uplata')";
    sqlite3_stmt *stmt = nullptr;
    int kod;
    pripremi(baza, sql, stmt);
    sqlite3_bind_int(stmt, 1, sqlite3_last_insert_rowid(baza));
    kod = sqlite3_step(stmt);
    if (kod != SQLITE_DONE) {
        std::string greska = std::string("Greška pri proknjižavanju uplate: ") + sqlite3_errmsg(baza);
        sqlite3_finalize(stmt);
        throw greska;
    }
    sqlite3_finalize(stmt);
}

void proknjiziStavku(sqlite3 *baza, int iznos, int idFil, int idRac) {
    const char *sql = "INSERT INTO Stavka (RedBroj, Datum, Vreme, Iznos, IdFil, IdRac) "
        "SELECT COALESCE(MAX(S.RedBroj), 0) + 1, DATE(), TIME(), ?, ?, ? "
        "FROM Stavka S "
        "WHERE S.IdRac = ?";
    sqlite3_stmt *stmt = nullptr;
    int kod;
    pripremi(baza, sql, stmt);
    sqlite3_bind_int(stmt, 1, iznos);
    sqlite3_bind_int(stmt, 2, idFil);
    sqlite3_bind_int(stmt, 3, idRac);
    sqlite3_bind_int(stmt, 4, idRac);
    izvrsiBezParametara(baza, "BEGIN TRANSACTION");
    kod = sqlite3_step(stmt);
    if (kod != SQLITE_DONE) {
        std::string greska = std::string("Greška pri proknjižavanju stavke: ") + sqlite3_errmsg(baza);
        sqlite3_finalize(stmt);
        throw greska;
    }
    sqlite3_finalize(stmt);
    proknjiziUplatu(baza);
    if (azurirajRacun(baza, idRac, iznos)) {
        std::cout << "Račun promenio status u aktivan. ";
    }
    izvrsiBezParametara(baza, "COMMIT TRANSACTION");
}

bool azurirajRacun(sqlite3 *baza, int idRac, int novIznos) {
    const char *sql1 = "SELECT Status, Stanje, DozvMinus FROM Racun"
        "WHERE IdRac = ?";
    const char *sql2 = "UPDATE Racun "
        "SET Status = ?1"
        "BrojStavki = (SELECT MAX(IdSta) FROM Stavka WHERE IdRac = ?2),"
        "Stanje = ?3"
        "WHERE IdRac = ?2";
    sqlite3_stmt *stmt = nullptr;
    int kod;
    pripremi(baza, sql1, stmt);
    sqlite3_bind_int(stmt,1,idRac);
    kod = sqlite3_step(stmt);
    if (kod != SQLITE_ROW) {
        std::string greska = std::string("Greška pri ažuriranju računa: ") + sqlite3_errmsg(baza);
        sqlite3_finalize(stmt);
        throw greska;
    }
    int staroStanje = sqlite3_column_int(stmt,1);
    int dMinus = sqlite3_column_int(stmt,2);
    const char *status = (const char*)sqlite3_column_text(stmt,0);
    sqlite3_finalize(stmt);

    stmt = nullptr;
    pripremi(baza, sql2, stmt);
    sqlite3_bind_text(stmt, 1, (staroStanje + novIznos > dMinus) ? "A" : status, 1, nullptr);
    sqlite3_bind_int(stmt, 2, idRac);
    sqlite3_bind_int(stmt, 3, staroStanje + novIznos);
    kod = sqlite3_step(stmt);
    if (kod != SQLITE_DONE) {
        std::string greska = std::string("Greška pri ažuriranju računa: ") + sqlite3_errmsg(baza);
        sqlite3_finalize(stmt);
        throw greska;
    }
    sqlite3_finalize(stmt);
    return staroStanje + novIznos > dMinus;
}

int main(void) {
    try {
        sqlite3 *baza = otvoriBazu("Banka.db");
        int idRac, idFil, iznos;
        std::cout << "Unesi ID računa: ";
        std::cin >> idRac;
        std::cout << "Unesi ID filijale: ";
        std::cin >> idFil;
        std::cout << "Unesi iznos: " ;
        std::cin >> iznos;
        proknjiziStavku(baza, iznos, idFil, idRac);
        std::cout << "Uspešno procesirana uplata. ";
        zatvoriBazu(baza);
    }
    catch (std::string &greska) {
        izvrsiBezParametara(baza, "ROLLBACK TRANSACTION");
        std::cout << "Desila se greška." << std::endl << greska << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}