#include "Database.h" // if (!_db.CheckSyntax(req)) // { // wxString s = req; // std::cout << s.mb_str() << " is invalid !\n" ; // code_if_syntax_fail; // return return_value; // } #define EXECUTE_SQL_UPDATE_WITH_CODE(req, return_value, code_if_fail, code_if_syntax_fail) \ do{\ try\ {\ _db.ExecuteUpdate(req);\ }\ catch (wxSQLite3Exception e)\ {\ std::cerr << e.GetMessage().mb_str() << "\n" ;\ code_if_fail; \ return return_value;\ }\ } while(0); #define EXECUTE_SQL_QUERY_WITH_CODE(req, res, return_value, code_if_fail, code_if_syntax_fail) \ do{\ try\ {\ res = _db.ExecuteQuery(req);\ }\ catch (wxSQLite3Exception e)\ {\ std::cerr << e.GetMessage().mb_str() << "\n" ;\ code_if_fail; \ return return_value;\ }\ } while(0); #define EXECUTE_SQL_QUERY(req, res, return_value) EXECUTE_SQL_QUERY_WITH_CODE(req, res, return_value, {}, {}) #define EXECUTE_SQL_UPDATE(req, return_value) EXECUTE_SQL_UPDATE_WITH_CODE(req, return_value, {}, {}) Database::Database() { std::ifstream bdd_file; bdd_file.open(BDD_FILE); if (!bdd_file) { CreateDatabase(); } else _db.Open(_(BDD_FILE)); bdd_file.close(); } void Database::CreateDatabase() { std::ifstream init_script; std::string line; wxString wxline; wxMessageBox(_("No database found, creating a new one"), _("KissCount"), wxICON_EXCLAMATION | wxOK ); init_script.open(INIT_SCRIPT); if (!init_script) { wxMessageBox(_(INIT_SCRIPT " not found, aborting"), _("Error"), wxICON_ERROR | wxOK ); throw "init.sql not found, aborting"; } _db.Open(_(BDD_FILE)); do { getline(init_script, line); wxline = wxString(line.c_str(), wxConvUTF8); wxline.Trim(false); if (!wxline.Length() || wxline.StartsWith(_("--"))) continue; if (!_db.CheckSyntax(wxline)) { std::cout << line << " is invalid !\n" ; continue; } try { _db.ExecuteUpdate(wxline); } catch (...) { wxMessageBox(_("Error creating original database"), _("Error"), wxICON_ERROR | wxOK ); remove(BDD_FILE); throw line; } } while (init_script); init_script.close(); } std::list Database::GetUsers() { std::list res; // Check whether value exists in table wxSQLite3ResultSet set ; EXECUTE_SQL_QUERY(_("SELECT name FROM user ORDER BY name"), set, res); while (set.NextRow()) { res.push_front(set.GetAsString(0)); } set.Finalize(); return res; } bool Database::IsValidUser(wxString user, wxString password) { bool res; blk_SHA_CTX sha_ctx; unsigned char sha[20]; wxString req, wxSHA; wxSQLite3ResultSet set; blk_SHA1_Init(&sha_ctx); blk_SHA1_Update(&sha_ctx, password.c_str(), password.Length()); blk_SHA1_Final(sha, &sha_ctx); for(int i=0; i<20; i++) wxSHA += wxString::Format(wxT("%02x"), (int)sha[i]); req = _("SELECT name FROM user WHERE name='") + user + _("' AND password='") + wxSHA + _("'"); EXECUTE_SQL_QUERY(req, set, false); res = set.NextRow() ; set.Finalize(); return res; } User* Database::LoadUser(wxString name) { wxSQLite3ResultSet set; wxString req; User* user; struct Account account; std::map::iterator it; req = _("SELECT * FROM user WHERE name='") + name + _("'"); EXECUTE_SQL_QUERY(req, set, NULL); if (!set.NextRow()) return NULL; user = new User(); user->_id = set.GetAsString(_("id")); user->_name = set.GetAsString(_("name")); user->_password = _("") ; // Security reasons set.GetAsString("password"); set.Finalize(); req = _("SELECT * FROM account WHERE user='") + user->_id + _("' ORDER BY default_account DESC, name ASC"); EXECUTE_SQL_QUERY_WITH_CODE(req, set, NULL, {delete user;}, {delete user;}); while (set.NextRow()) { account.id = set.GetAsString(_("id")); account.name = set.GetAsString(_("name")); account.number = set.GetAsString(_("number")); account.shared = set.GetBool(_("shared")); account._default = set.GetBool(_("default_account")); user->_accounts[account.id] = account; } set.Finalize(); if (!user->_accounts.empty()) { it = user->_accounts.begin(); req = _("SELECT DISTINCT year FROM account_amount WHERE account IN('") + it->first; it++; for (;it != user->_accounts.end(); it++) { req += _("', '") + it->first ; } req += _("') ORDER BY year ASC"); EXECUTE_SQL_QUERY_WITH_CODE(req, set, NULL, {delete user;}, {delete user;}); while (set.NextRow()) { user->_operations[set.GetInt(_("year"))] = NULL; } set.Finalize(); } req = _("SELECT id, value FROM preference WHERE type='category' AND name='name' AND user='") + user->_id + _("' ORDER BY value ASC"); EXECUTE_SQL_QUERY_WITH_CODE(req, set, NULL, {delete user;}, {delete user;}); while (set.NextRow()) user->_preferences._categories[set.GetAsString(_("id"))] = set.GetAsString(_("value")); set.Finalize(); return user; } void Database::LoadYear(User* user, int year) { wxSQLite3ResultSet set; wxString req; std::map::iterator it; if (user->_operations[year] == NULL) user->_operations[year] = new std::map >(); it = user->_accounts.begin(); req = _("SELECT * FROM operation WHERE account IN('") + it->first; it++; for (;it != user->_accounts.end(); it++) { req += _("', '") + it->first ; } req += _("') ORDER BY fix_cost DESC, year,month,day ASC"); EXECUTE_SQL_QUERY(req, set, ); while (set.NextRow()) { operation op; op.id = set.GetAsString(_("id")); op.account = set.GetAsString(_("account")); op.day = set.GetInt(_("day")); op.month = set.GetInt(_("month")); op.year = set.GetInt(_("year")); op.amount = set.GetDouble(_("amount")); op.description = set.GetAsString(_("description")); op.category = set.GetAsString(_("category")); op.fix_cost = set.GetBool(_("fix_cost")); (*user->_operations[op.year])[op.month].push_back(op); } set.Finalize(); } double Database::GetAccountAmount(wxString id, int month, int year) { wxSQLite3ResultSet set; wxString req; double res; req = _("SELECT amount FROM account_amount WHERE account='") + id ; req += _("' AND month='") + wxString::Format(_("%d"), month); req += _("' AND year='") + wxString::Format(_("%d"), year); req += _("'"); EXECUTE_SQL_QUERY(req , set, 0.0); if (set.NextRow()) res = set.GetDouble(_("amount")); else res = 0.0; set.Finalize(); return res; } void Database::UpdateOperation(struct operation op) { wxString req; req = _("UPDATE operation SET ") ; req += _("account='") + op.account + _("'"); req += _(", year='") + wxString::Format(_("%d"), op.year) + _("'"); req += _(", month='") + wxString::Format(_("%d"), op.month) + _("'"); req += _(", day='") + wxString::Format(_("%d"), op.day) + _("'"); req += _(", amount='") + wxString::Format(_("%.2lf"), op.amount) + _("'"); req += _(", description=\"") + op.description + _("\""); req += _(", category='") + op.category + _("'"); req += _(" WHERE id='") + op.id + _("'"); //std::cout << req.mb_str() << "\n"; EXECUTE_SQL_UPDATE(req, ); } void Database::AddOperation(User* user, struct operation op) { wxString req; req = _("INSERT INTO operation ('user', 'account', 'year', 'month', 'day', 'amount', 'description', 'category', 'fix_cost') VALUES ('") ; req += user->_id + _("'"); req += _(", '") + op.account + _("'"); req += _(", '") + wxString::Format(_("%d"), op.year) + _("'"); req += _(", '") + wxString::Format(_("%d"), op.month) + _("'"); req += _(", '") + wxString::Format(_("%d"), op.day) + _("'"); req += _(", '") + wxString::Format(_("%.2lf"), op.amount) + _("'"); req += _(", \"") + op.description + _("\""); req += _(", '") + op.category + _("'"); if (op.fix_cost) req += _(", '1'") ; else req += _(", '0'") ; req += _(")"); EXECUTE_SQL_UPDATE(req, ); } void Database::DeleteOperation(struct operation op) { wxString req; req = _("DELETE FROM operation WHERE id='") + op.id + _("'"); EXECUTE_SQL_UPDATE(req, ); } void Database::SetAccountAmount(int month, int year, wxString accountId, double amount) { wxString req; req = _("UPDATE account_amount SET ") ; req += _("amount='") + wxString::Format(_("%.2lf"), amount) + _("'"); req += _(" WHERE id='") + accountId + _("'"); req += _(" AND year='") + wxString::Format(_("%d"), year) + _("'"); req += _(" AND month='") + wxString::Format(_("%d"), month) + _("'"); EXECUTE_SQL_UPDATE(req, ); }