/* Copyright 2010-2016 Grégory Soutadé This file is part of KissCount. KissCount is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. KissCount is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with KissCount. If not, see . */ #include #include #include #include #include #include #include #include #include #include "Database.hpp" Database::Database(const char* filename, KissCount* kiss) : _kiss(kiss) { std::ifstream bdd_file; QString sPath = GetDatabaseHome() + GetDatabaseFile(); _db = QSqlDatabase::addDatabase("QSQLITE"); if (filename) { bdd_file.open(filename, std::ifstream::in); if (!bdd_file.good()) { QMessageBox::critical(0, _("Error"), _("Unable to open database")); throw std::string("Unable to open ") + filename; } _db.setDatabaseName(filename); if (!_db.open()) { QMessageBox::critical(0, _("Error"), _("Unable to open database")); throw std::string("Unable to open ") + filename; } } else { // If default BDD file, assume this can be the first load bdd_file.open(sPath.toStdString().c_str(), std::ifstream::in); if (!bdd_file.good()) { CreateDatabase(); } else { _db.setDatabaseName(sPath); if (!_db.open()) { QMessageBox::critical(0, _("Error"), _("Unable to open database")); throw std::string("Unable to open ") + sPath.toStdString(); } } } bdd_file.close(); CheckDatabaseVersion(); } void Database::CreateDatabase() { QFile init_script(INIT_SCRIPT); QString sPath = GetDatabaseHome() + GetDatabaseFile(); QDir dirname( GetDatabaseHome()); QFile file(sPath); QString message; message = _("A new database will be created, continue ?"); if (QMessageBox::question(0, "KissCount", message, QMessageBox::Yes|QMessageBox::No) == QMessageBox::No) throw std::string("Abort") ; if (!init_script.exists() || !init_script.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox::critical(0, _("Error"), INIT_SCRIPT + _(" not found, aborting")); throw "init.sql not found, aborting"; } if (!dirname.exists() && !dirname.mkdir(dirname.absolutePath())) { QMessageBox::critical(0, _("Error"), _("Unable to Create ") + dirname.absolutePath() ); throw std::string("Unable to create ") + dirname.absolutePath().toStdString(); } if (!file.exists() && !file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QMessageBox::critical(0, _("Error"), _("Unable to Create ") + QString(sPath)); throw std::string("Unable to create ") + sPath.toStdString(); } file.close(); _db.setDatabaseName(sPath); if (!_db.open()) { QMessageBox::critical(0, _("Error"), _("Unable to open Database")); throw std::string("Unable to open ") + sPath.toStdString(); } while (!init_script.atEnd()) { QByteArray line = init_script.readLine().trimmed(); QSqlQuery query; if (line.isEmpty() || line.startsWith("--")) continue; // if (!query.isValid()) // { // std::cout << QString(line).toStdString() << " is invalid !\n" ; // continue; // } if (!query.exec(QString(line))) { QMessageBox::critical(0, _("Error"), _("Error creating original database")); init_script.close(); file.remove(); std::cout << QString(line).toStdString() << " is invalid !\n" ; throw QString(line); } } init_script.close(); } QString Database::HashPassword(const QString& password) { return QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Sha1).toHex(); } std::list Database::GetUsers() { std::list res; QSqlQuery query(_db); EXECUTE_SQL_QUERY(QString("SELECT name FROM user ORDER BY name"), res); while (query.next()) res.push_back(query.value(0).toString()); return res; } bool Database::IsValidUser(const QString& user, const QString& password) { QSqlQuery query(_db); query.prepare("SELECT name FROM user WHERE name=:id AND password=:password"); query.bindValue(":id", user); query.bindValue(":password", HashPassword(password)); EXECUTE_PREPARED_SQL_QUERY(false); return query.next(); } static inline void fillOperation(Operation* op, const QSqlRecord& set) { op->id = set.value("id").toInt(); op->parent = set.value("parent").toInt(); op->account = set.value("account").toInt(); op->day = set.value("day").toInt(); op->month = set.value("month").toInt(); op->year = set.value("year").toInt(); op->amount = set.value("amount").toInt(); op->description = set.value("description").toString(); op->category = set.value("category").toInt(); op->tag = set.value("tag").toInt(); op->fix_cost = set.value("fix_cost").toBool(); op->checked = set.value("checked").toBool(); op->transfert = set.value("transfert").toInt(); op->formula = set.value("formula").toString(); op->meta = set.value("meta").toBool(); op->_virtual = set.value("virtual").toBool(); } static inline void fillAccount(Account* account, const QSqlRecord& set) { account->id = set.value("id").toInt(); account->name = set.value("name").toString(); account->number = set.value("number").toString(); account->shared = set.value("shared").toBool(); account->blocked = set.value("blocked").toBool(); account->_default = set.value("default_account").toBool(); account->_virtual = set.value("virtual").toBool(); account->is_owner = true; account->hidden = set.value("hidden").toBool(); account->start_date = set.value("start").toDate(); account->end_date = set.value("end").toDate(); } static inline void fillCategory(Category* category, const QSqlRecord& set) { category->id = set.value("id").toInt(); category->parent = set.value("parent").toInt(); category->name = set.value("name").toString(); category->backcolor = QColor(set.value("backcolor").toString()); category->forecolor = QColor(set.value("forecolor").toString()); category->font = set.value("font").toString(); category->fix_cost = set.value("fix_cost").toBool(); } static inline void fillTag(Tag* tag, const QSqlRecord& set) { tag->id = set.value("id").toInt(); tag->name = set.value("name").toString(); } User* Database::LoadUser(const QString& name) { User* user; Account account; Category category; Tag tag; ImportPattern importPattern; QString req; QSqlRecord set; QSqlQuery query(_db); std::vector::iterator it; query.prepare("SELECT * FROM user WHERE name=:name"); query.bindValue(":name", name); EXECUTE_PREPARED_SQL_QUERY(0); if (!query.next()) return 0; user = new User(this); set = query.record(); user->_id = set.value("id").toInt(); user->_name = set.value("name").toString(); user->_password = "" ; // Security reasons set.value("password").toString(); query.clear(); req = QString("SELECT * FROM account WHERE user='%1' ORDER BY default_account DESC, hidden, blocked, virtual, name ASC").arg(user->_id); EXECUTE_SQL_QUERY_WITH_CODE(req, 0, {delete user;}, {delete user;}); while (query.next()) { set = query.record(); fillAccount(&account, set); user->_accounts.push_back(account); } query.clear(); req = QString("SELECT * FROM account WHERE id IN (SELECT account FROM shared_account WHERE user='%1') ORDER BY default_account DESC, hidden, blocked, virtual, name ASC").arg(user->_id); EXECUTE_SQL_QUERY_WITH_CODE(req, 0, {delete user;}, {delete user;}); while (query.next()) { set = query.record(); fillAccount(&account, set); account.is_owner = false; user->_accounts.push_back(account); } query.clear(); if (!user->_accounts.empty()) { it = user->_accounts.begin(); req = "SELECT DISTINCT year FROM operation WHERE account IN('" + QString::number(it->id); it++; for (;it != user->_accounts.end(); it++) { req += "', '" + QString::number(it->id) ; } req += "')"; req += " OR user='" + QString::number(user->_id) + "'"; req += " ORDER BY year ASC"; EXECUTE_SQL_QUERY_WITH_CODE(req, 0, {delete user;}, {delete user;}); while (query.next()) { set = query.record(); user->_operations[set.value("year").toInt()] = 0; } } req = QString("SELECT * FROM category WHERE user='%1' ORDER BY fix_cost DESC, name ASC").arg(user->_id); EXECUTE_SQL_QUERY_WITH_CODE(req, 0, {delete user;}, {delete user;}); while (query.next()) { set = query.record(); fillCategory(&category, set); user->_categories.push_back(category); user->_categoriesFonts.push_back(_kiss->ExtractFont(category.font)); } query.clear(); req = QString("SELECT * FROM tag WHERE user='%1' ORDER BY name ASC").arg(user->_id); EXECUTE_SQL_QUERY_WITH_CODE(req, 0, {delete user;}, {delete user;}); while (query.next()) { set = query.record(); fillTag(&tag, set); user->_tags.push_back(tag); } query.clear(); req = QString("SELECT name, value FROM preference WHERE user='%1' ORDER BY value ASC").arg(user->_id); EXECUTE_SQL_QUERY_WITH_CODE(req, 0, {delete user;}, {delete user;}); while (query.next()) { set = query.record(); user->_preferences[set.value("name").toString()] = set.value("value").toString(); } query.clear(); req = QString("SELECT * FROM import_pattern WHERE user='%1'").arg(user->_id); EXECUTE_SQL_QUERY_WITH_CODE(req, 0, {delete user;}, {delete user;}); while (query.next()) { set = query.record(); importPattern.pattern = set.value("pattern").toString(); importPattern.account = set.value("account").toInt(); importPattern.category = set.value("category").toInt(); user->_importPatterns[set.value("description").toString()] = importPattern; } query.clear(); return user; } void Database::LoadYear(User* user, int year) { QSqlRecord set; QString req; std::vector::iterator it; QSqlQuery query(_db); if (user->_operations[year] == 0) user->_operations[year] = new std::map >(); if (!user->_accounts.size()) return; it = user->_accounts.begin(); req = "SELECT * FROM operation WHERE (account IN('" + QString::number(it->id); it++; for (;it != user->_accounts.end(); it++) { req += "', '" + QString::number(it->id) ; } req += "')"; req += " OR user='" + QString::number(user->_id) + "')"; req += " AND year='" + QString::number(year) + "'"; req += " ORDER BY fix_cost DESC, year, month ASC, day "; req += user->_preferences["operation_order"]; EXECUTE_SQL_QUERY(req, ); while (query.next()) { Operation op; set = query.record(); fillOperation(&op, set); (*user->_operations[op.year])[op.month].push_back(op); } user->ResolveGroups(year); query.clear(); } int Database::GetAccountAmount(int id, int month, int year, bool* had_value, bool create_if_not_exsits) { QSqlRecord set; QString req; int res = 0; QSqlQuery query(_db); req = QString("SELECT amount FROM account_amount WHERE account='%1' AND month='%2' AND year='%3'") .arg(QString::number(id), QString::number(month), QString::number(year)) ; EXECUTE_SQL_QUERY(req, 0); if (query.next()) { set = query.record(); res = set.value("amount").toInt(); if (had_value) *had_value = true; } else { if (create_if_not_exsits) SetAccountAmount(id, month, year, 0); if (had_value) *had_value = false; } query.clear(); return res; } int Database::CalcAccountAmount(int id, int month, int year, bool* had_values) { QSqlRecord set; QString req; int res = 0; QSqlQuery query(_db); req = QString("SELECT SUM(id) AS id, SUM(amount) AS amount FROM operation WHERE account='%1' AND month='%2' AND year='%3' AND meta='0'"). arg(QString::number(id), QString::number(month), QString::number(year)) ; EXECUTE_SQL_QUERY(req, 0); if (query.next()) { set = query.record(); res = set.value("amount").toInt(); if (had_values) *had_values = set.value("id").toInt() > 0 ; } else { if (had_values) *had_values = false; } query.clear(); return res; } bool Database::GetOperation(int id, Operation* op) { QSqlRecord set; QString req; QSqlQuery query(_db); req = QString("SELECT * FROM operation WHERE id='%1'").arg(QString::number(id)); EXECUTE_SQL_QUERY(req, false); if (!query.next()) return false; set = query.record(); fillOperation(op, set); return true; } void Database::LinkOrUnlinkOperation(User* user, Operation& op) { Operation linked; QString req, v; QSqlRecord set; Account account, account2; bool _virtual; QSqlQuery query(_db); if (op.meta) return; account = user->GetAccount(op.account); if (op.transfert) { // No one or not linked if (!GetOperation(op.transfert, &linked) || op.description != linked.description || op.amount != -linked.amount || op.account == linked.account) { op._virtual = account._virtual; req = QString("UPDATE operation SET transfert='', virtual='%1' WHERE id='%2'").arg(op._virtual?"1":"0", op.id); EXECUTE_SQL_UPDATE(req, ); op.transfert = 0; return; } } // Not Linked else { req = QString("SELECT id FROM operation WHERE transfert='%1'").arg(op.id); EXECUTE_SQL_QUERY(req, ); if (query.next()) { op._virtual = account._virtual; set = query.record(); req = QString("UPDATE operation SET transfert='', virtual='%1' WHERE id='%2'").arg(op._virtual?"1":"0", set.value("id").toString()); query.clear(); EXECUTE_SQL_UPDATE(req, ); } else query.clear(); req = QString("SELECT id, account FROM operation WHERE description=\"%1\" AND month='%2' AND year='%3' AND amount='%4' AND meta='0' AND account !='%5' AND transfert=''") .arg(op.description, QString::number(op.month), QString::number(op.year), v.sprintf("%d", -op.amount), QString::number(op.account)); EXECUTE_SQL_QUERY(req, ); // Don't need to link if (!query.next()) return ; set = query.record(); // Link linked.id = set.value("id").toInt(); op.transfert = linked.id; account2 = user->GetAccount(set.value("account").toInt()); _virtual = account._virtual || account2._virtual; query.clear(); req = QString("UPDATE operation SET transfert='%1', virtual='%2' WHERE id='%3'") .arg((linked.id) ? QString::number(linked.id) : "", QString::number(_virtual), QString::number(op.id)); EXECUTE_SQL_UPDATE(req, ); query.clear(); req = QString("UPDATE operation SET transfert='%1', virtual='%2' WHERE id='%3'") .arg((op.id) ? QString::number(op.id) : "", QString::number(_virtual), QString::number(linked.id)); EXECUTE_SQL_UPDATE(req, ); op._virtual = _virtual; query.clear(); } } void Database::UpdateOperation(User* user, Operation& op, bool checkTransfert) { QString req, v; QSqlQuery query(_db); if (checkTransfert) LinkOrUnlinkOperation(user, op); ESCAPE_CHARS(op.description); req = "UPDATE operation SET parent='%1', account='%2', year='%3', month='%4', day='%5', amount='%6', description=:description, category='%8', tag='%9'" ; req = req.arg((op.parent) ? QString::number(op.parent) : "", QString::number(op.account), QString::number(op.year), QString::number(op.month), QString::number(op.day), v.sprintf("%d", op.amount), QString::number(op.category), QString::number(op.tag)); req += ", fix_cost='%1', checked='%2', transfert='%3', meta='%4', virtual='%5', formula=:formula WHERE id='%7'"; req = req.arg(QString::number(op.fix_cost), QString::number(op.checked), (op.transfert) ? QString::number(op.transfert): "", QString::number(op.meta), QString::number(op._virtual), QString::number(op.id)); query.prepare(req); query.bindValue(":description", op.description); query.bindValue(":formula", op.formula); EXECUTE_PREPARED_SQL_UPDATE(); if (checkTransfert) LinkOrUnlinkOperation(user, op); } int Database::AddOperation(User* user, Operation& op, bool checkTransfert) { QString req, v; QSqlRecord set; QSqlQuery query(_db); ESCAPE_CHARS(op.description); req = "INSERT INTO operation ('user', 'parent', 'account', 'year', 'month', 'day', 'amount', 'description', 'category', 'tag', 'fix_cost', 'formula', 'transfert', 'meta', 'virtual', 'checked') VALUES ('%1', '%2', '%3', '%4', '%5', '%6', '%7', :description" ; req = req.arg(QString::number(user->_id), (op.parent) ? QString::number(op.parent): "", QString::number(op.account), QString::number(op.year), QString::number(op.month), QString::number(op.day), v.sprintf("%d", op.amount)); req += ", '%1', '%2', '%3', :formula, '%4', '%5', '%6', '%7')"; req = req.arg(QString::number(op.category), QString::number(op.tag), QString::number(op.fix_cost), (op.transfert) ? QString::number(op.transfert): "", QString::number(op.meta), QString::number(op._virtual), QString::number(op.checked)); query.prepare(req); query.bindValue(":description", op.description); query.bindValue(":formula", op.formula); if (!query.exec()) { QMessageBox::critical(0, _("Error"), _("Update failed !\n") + req); return 0; } op.id = query.lastInsertId().toInt(); if (checkTransfert) LinkOrUnlinkOperation(user, op); return op.id; } void Database::DeleteOperation(User* user, Operation& op) { QSqlQuery query(_db); QString req = QString("DELETE FROM operation WHERE id='%1'").arg(op.id); EXECUTE_SQL_UPDATE(req, ); LinkOrUnlinkOperation(user, op); } void Database::DeleteOperations(User* user, int month, int year) { QString req; std::vector::iterator it; it = user->_accounts.begin(); req = "DELETE FROM account_amount WHERE account IN('" + QString::number(it->id); it++; for (;it != user->_accounts.end(); it++) { req += "', '" + QString::number(it->id) ; } req += "')"; req += " AND year='" + QString::number(year) + "'"; if (month != -1) req += " AND month='" + QString::number(month) + "'"; EXECUTE_SQL_UPDATE(req, ); it = user->_accounts.begin(); req = "DELETE FROM operation WHERE (account IN('" + QString::number(it->id); it++; for (;it != user->_accounts.end(); it++) { req += "', '" + QString::number(it->id) ; } req += "')"; req += " OR user='" + QString::number(user->_id) + "')"; req += " AND year='" + QString::number(year) + "'"; if (month != -1) req += " AND month='" + QString::number(month) + "'"; EXECUTE_SQL_UPDATE(req, ); } bool Database::LoadOperation(User* user, int id) { QSqlRecord set; QString req; bool ret = false; std::vector::iterator it; QSqlQuery query(_db); req = QString("SELECT * FROM operation WHERE id='%1'").arg(id); EXECUTE_SQL_QUERY(req, false); if (query.next()) { Operation op; set = query.record(); fillOperation(&op, set); if (user->_operations[op.year]) { for (it = (*user->_operations[op.year])[op.month].begin(); it != (*user->_operations[op.year])[op.month].end(); it++) { if (!op.fix_cost && it->fix_cost) continue; if (op.fix_cost && !it->fix_cost) { it--; break; } if (it->day > op.day) { it--; break; } } if (it == (*user->_operations[op.year])[op.month].end()) (*user->_operations[op.year])[op.month].push_back(op); else (*user->_operations[op.year])[op.month].insert(it, op); // if (op.fix_cost) // else // (*user->_operations[op.year])[op.month].push_back(op); ret = true; } } query.clear(); return ret; } // We may not have access to all operations if we have a shared account int Database::MetaAmount(int id) { QSqlRecord set; QString req; int res = 0; QSqlQuery query(_db); req = QString("SELECT SUM(amount) as amount FROM operation WHERE parent='%1'").arg(id); EXECUTE_SQL_QUERY(req, false); if (query.next()) { set = query.record(); res = set.value("amount").toInt(); } query.clear(); return res; } // Idem int Database::MetaPositiveAmount(int id) { QSqlRecord set; QString req; int res = 0; QSqlQuery query(_db); req = QString("SELECT SUM(amount) as amount FROM operation WHERE amount > 0 AND parent='%1'").arg(id); EXECUTE_SQL_QUERY(req, false); if (query.next()) { set = query.record(); res = set.value("amount").toInt(); } query.clear(); return res; } void Database::SetAccountAmount(int accountId, int month, int year, int amount) { QString req, v; QSqlQuery query(_db); req = "INSERT or REPLACE INTO account_amount ('account', 'year', 'month', 'amount') VALUES ('%1', '%2', '%3', '%4')" ; req = req.arg(QString::number(accountId), QString::number(year), QString::number(month), v.sprintf("%d", amount)); EXECUTE_SQL_UPDATE(req, ); } int Database::AddAccount(User* user, Account& ac) { QString req; QSqlQuery query(_db); int id; req = "INSERT INTO account ('user', 'name', 'number', 'shared', 'blocked', 'default_account', 'virtual', 'hidden') VALUES " ; req += "('%1', '%2', '%3', '%4', '%5', '%6', '%7', '%8')"; req = req.arg(QString::number(user->_id), ac.name, ac.number, QString::number(ac.shared), QString::number(ac.blocked), QString::number(ac._default), QString::number(ac._virtual), QString::number(ac.hidden)); if (!query.exec(req)) { QMessageBox::critical(0, _("Error"), _("Update failed !\n") + req); std::cerr << __FUNCTION__ << "\n" ; std::cerr << req.toStdString() << "\n" ; std::cerr << query.lastError().text().toStdString() << "\n" ; return 0; } id = query.lastInsertId().toInt(); req = "UPDATE account SET start='%1', end='%2' WHERE id='%3'"; req = req.arg(ac.start_date.toString("yyyy-MM-dd"), ac.end_date.toString("yyyy-MM-dd"), QString::number(id)); EXECUTE_SQL_UPDATE(req, 0); return id; } void Database::UpdateAccount(Account& ac) { QString req; req = "UPDATE account SET name='%1', number='%2', shared='%3', blocked='%4', default_account='%5', virtual='%6', hidden='%7' WHERE id='%8'" ; req = req.arg(ac.name, ac.number, QString::number(ac.shared), QString::number(ac.blocked), QString::number(ac._default), QString::number(ac._virtual), QString::number(ac.hidden), QString::number(ac.id)); EXECUTE_SQL_UPDATE(req, ); req = "UPDATE account SET start='%1', end='%2' WHERE id='%3'" ; req = req.arg(ac.start_date.toString("yyyy-MM-dd"), ac.end_date.toString("yyyy-MM-dd"), QString::number(ac.id)); EXECUTE_SQL_UPDATE(req, ); if (!ac.shared && ac.is_owner) { req = QString("DELETE FROM shared_account WHERE account='%1'").arg(ac.id); EXECUTE_SQL_UPDATE(req, ); } } void Database::DeleteAccount(User* user, Account& ac, int replacement) { QString req; if (ac.is_owner) { if (ac.shared) { req = QString("DELETE FROM shared_account WHERE account='%1'").arg(ac.id); EXECUTE_SQL_UPDATE(req, ); } req = QString("DELETE FROM account WHERE id='%1'").arg(ac.id); EXECUTE_SQL_UPDATE(req, ); req = QString("DELETE FROM account_amount WHERE account='%1'").arg(ac.id); EXECUTE_SQL_UPDATE(req, ); req = QString("UPDATE operation SET account='%1' WHERE account='%2'").arg(QString::number(replacement), QString::number(ac.id)); // req += wxT(", transfert='0'"); EXECUTE_SQL_UPDATE(req, ); } else RemoveSharedAccount(ac, user->_id); } void Database::AddSharedAccount(Account& ac, const QString& granted) { QString req; QSqlRecord set; QSqlQuery query(_db); req = QString("SELECT id FROM user WHERE name=:name"); query.prepare(req); query.bindValue(":name", granted); EXECUTE_PREPARED_SQL_QUERY(); query.next(); set = query.record(); req = QString("INSERT INTO shared_account ('account', 'user') VALUES ('%1', '%2')").arg(QString::number(ac.id), set.value("id").toString()); query.clear(); EXECUTE_SQL_UPDATE(req, ); if (!ac.shared) { ac.shared = true; UpdateAccount(ac); } } void Database::RemoveSharedAccount(Account& ac, int granted) { QString req; QSqlRecord set; QSqlQuery query(_db); req = QString("DELETE FROM shared_account WHERE user='%1' AND account='%2'").arg(QString::number(granted), QString::number(ac.id)); EXECUTE_SQL_UPDATE(req, ); req = QString("SELECT COUNT(user) AS cnt FROM shared_account WHERE account='%1'").arg(ac.id); EXECUTE_SQL_QUERY(req, ); query.next(); set = query.record(); if (!set.value("cnt").toInt()) { ac.shared = false; UpdateAccount(ac); } } int Database::AddCategory(User* user, Category& category) { QString req; QString backcolor, forecolor; QSqlQuery query(_db); backcolor = "#" ; backcolor += QString::number(category.backcolor.red(), 16); backcolor += QString::number(category.backcolor.green(), 16); backcolor += QString::number(category.backcolor.blue(), 16); forecolor = "#" ; forecolor += QString::number(category.forecolor.red(), 16); forecolor += QString::number(category.forecolor.green(), 16); forecolor += QString::number(category.forecolor.blue(), 16); req = "INSERT INTO category ('user', 'parent', 'name', 'backcolor', 'forecolor', 'font', 'fix_cost') VALUES ('" ; req += QString::number(user->_id) + "'"; req += ", '" + QString::number(category.parent) + "'"; req += ", :name"; req += ", '" + backcolor + "'"; req += ", '" + forecolor + "'"; req += ", '" + category.font + "'"; if (category.fix_cost) req += ", '1'"; else req += ", '0'"; req += ")"; query.prepare(req); query.bindValue(":name", category.name); if (!query.exec()) { QMessageBox::critical(0, _("Error"), _("Update failed !\n") + req); std::cerr << __FUNCTION__ << "\n" ; std::cerr << req.toStdString() << "\n" ; std::cerr << query.lastError().text().toStdString() << "\n" ; return 0; } return query.lastInsertId().toInt(); } void Database::UpdateCategory(Category& category) { QString req, tmp; QString backcolor, forecolor; QSqlQuery query(_db); backcolor = "#" ; tmp = QString::number(category.backcolor.red(), 16); if (tmp.length() == 1) tmp = "0" + tmp; backcolor += tmp; tmp = QString::number(category.backcolor.green(), 16); if (tmp.length() == 1) tmp = "0" + tmp; backcolor += tmp; tmp = QString::number(category.backcolor.blue(), 16); if (tmp.length() == 1) tmp = "0" + tmp; backcolor += tmp; forecolor = "#" ; tmp = QString::number(category.forecolor.red(), 16); if (tmp.length() == 1) tmp = "0" + tmp; forecolor += tmp; tmp = QString::number(category.forecolor.green(), 16); if (tmp.length() == 1) tmp = "0" + tmp; forecolor += tmp; tmp = QString::number(category.forecolor.blue(), 16); if (tmp.length() == 1) tmp = "0" + tmp; forecolor += tmp; req = "UPDATE category SET" ; req += " parent='" + QString::number(category.parent) + "'"; req += ", name=:name"; req += ", backcolor='" + backcolor + "'"; req += ", forecolor='" + forecolor + "'"; req += ", font='" + category.font + "'"; if (category.fix_cost) req += ", fix_cost='1'"; else req += ", fix_cost='0'"; req += " WHERE id='" + QString::number(category.id) + "'"; query.prepare(req); query.bindValue(":name", category.name); EXECUTE_PREPARED_SQL_UPDATE(); } void Database::DeleteCategory(User* user, Category& category, int replacement) { QString req; req = QString("DELETE FROM category WHERE id='%1'").arg(category.id); EXECUTE_SQL_UPDATE(req, ); req = QString("UPDATE category SET parent='' WHERE parent='%1'").arg(category.id) ; EXECUTE_SQL_UPDATE(req, ); req = QString("UPDATE operation SET category='%1' WHERE category='%2' AND user='%3'") .arg(QString::number(replacement), QString::number(category.id), QString::number(user->_id)); EXECUTE_SQL_UPDATE(req, ); if (replacement == user->_categories[0].id) { req = QString("UPDATE operation SET fix_cost='1' WHERE category='%1'").arg(replacement); EXECUTE_SQL_UPDATE(req, ); } } bool Database::LoadCategory(int id, const QString& name, Category& category) { QSqlRecord set; QString req; QSqlQuery query(_db); bool ret = false ; if (id) { req = QString("SELECT * FROM category WHERE id='%1'").arg(id); EXECUTE_SQL_QUERY(req, false); } else { req = QString("SELECT * FROM category WHERE name=:name"); query.prepare(req); query.bindValue(":name", name); EXECUTE_PREPARED_SQL_QUERY(false); } if (query.next()) { set = query.record(); fillCategory(&category, set); ret = true; } query.clear(); return ret; } int Database::AddTag(User* user, Tag& tag) { QString req; QString backcolor, forecolor; QSqlQuery query(_db); req = "INSERT INTO tag ('user', 'name') VALUES ('" ; req += QString::number(user->_id) + "'"; req += ", :name"; req += ")"; query.prepare(req); query.bindValue(":name", tag.name); if (!query.exec()) { QMessageBox::critical(0, _("Error"), _("Update failed !\n") + req); std::cerr << __FUNCTION__ << "\n" ; std::cerr << req.toStdString() << "\n" ; std::cerr << query.lastError().text().toStdString() << "\n" ; return 0; } return query.lastInsertId().toInt(); } void Database::UpdateTag(Tag& tag) { QString req; QSqlQuery query(_db); req = "UPDATE tag SET" ; req += "name=:name"; req += " WHERE id='" + QString::number(tag.id) + "'"; query.prepare(req); query.bindValue(":name", tag.name); EXECUTE_PREPARED_SQL_UPDATE(); } void Database::DeleteTag(User* user, Tag& tag, int replacement) { QString req; req = QString("DELETE FROM tag WHERE id='%1'").arg(tag.id); EXECUTE_SQL_UPDATE(req, ); req = QString("UPDATE operation SET tag='%1' WHERE tag='%2' AND user='%3'") .arg(QString::number(replacement), QString::number(tag.id), QString::number(user->_id)); EXECUTE_SQL_UPDATE(req, ); } bool Database::LoadTag(int id, const QString& name, Tag& tag) { QSqlRecord set; QString req; QSqlQuery query(_db); bool ret = false ; if (id) { req = QString("SELECT * FROM tag WHERE id='%1'").arg(id); EXECUTE_SQL_QUERY(req, false); } else { req = QString("SELECT * FROM tag WHERE name=:name"); query.prepare(req); query.bindValue(":name", name); EXECUTE_PREPARED_SQL_QUERY(false); } if (query.next()) { set = query.record(); fillTag(&tag, set); ret = true; } query.clear(); return ret; } std::map > Database::GetAllOperations(User* user) { QString req, req2, reqUnion; QSqlRecord set; QSqlQuery query(_db),query2(_db); std::vector::iterator it; std::map > res; int year; if (!user->_accounts.empty()) { it = user->_accounts.begin(); req = "SELECT DISTINCT year FROM account_amount WHERE account IN('" + QString::number(it->id); it++; for (;it != user->_accounts.end(); it++) { req += "', '" + QString::number(it->id) ; } req += "')"; it = user->_accounts.begin(); req2 = "SELECT DISTINCT year FROM operation WHERE account IN('" + QString::number(it->id); it++; for (;it != user->_accounts.end(); it++) { req2 += "', '" + QString::number(it->id) ; } req2 += "')"; req2 += " OR user='" + QString::number(user->_id) + "'"; req2 += " ORDER BY year ASC"; reqUnion = req + " UNION " + req2; EXECUTE_SQL_QUERY(reqUnion, res); query2 = query; while (query2.next()) { set = query2.record(); year = set.value("year").toInt(); it = user->_accounts.begin(); req = "SELECT DISTINCT month FROM account_amount WHERE account IN('" + QString::number(it->id); it++; for (;it != user->_accounts.end(); it++) { req += "', '" + QString::number(it->id) ; } req += "')"; req += " AND year='" + QString::number(year) + "'"; it = user->_accounts.begin(); req2 = "SELECT DISTINCT month FROM operation WHERE (account IN('" + QString::number(it->id); it++; for (;it != user->_accounts.end(); it++) { req2 += "', '" + QString::number(it->id) ; } req2 += "')"; req2 += " OR user='" + QString::number(user->_id) + "')"; req2 += " AND year='" + QString::number(year) + "'"; req2 += " ORDER BY month ASC"; reqUnion = req + " UNION " + req2; query.clear(); EXECUTE_SQL_QUERY(reqUnion, res); while (query.next()) { set = query.record(); res[year].push_back(set.value("month").toInt()); } query.clear(); } query2.clear(); } return res; } void Database::GenerateMonth(User* user, int monthFrom, int yearFrom, int monthTo, int yearTo) { std::vector::iterator it; QString req, v; QSqlRecord set; int amount; QSqlQuery query(_db); for (it = user->_accounts.begin(); it != user->_accounts.end(); it++) { amount = 0; req = "SELECT SUM(amount) AS total FROM operation WHERE account='%1' AND year='%2' AND month='%3' AND meta='0'" ; req = req.arg(QString::number(it->id), QString::number(yearFrom), QString::number(monthFrom)); EXECUTE_SQL_QUERY(req, ); if (query.next()) { set = query.record(); amount += set.value("total").toInt(); } query.clear(); req = "SELECT amount FROM account_amount WHERE account='%1' AND year='%2' AND month='%3'" ; req = req.arg(QString::number(it->id), QString::number(yearFrom), QString::number(monthFrom)); EXECUTE_SQL_QUERY(req, ); if (query.next()) { set = query.record(); amount += set.value("amount").toInt(); } query.clear(); req = "INSERT INTO account_amount ('account', 'year', 'month', 'amount') VALUES " ; req += "('%1', '%2', '%3', '%4')"; req = req.arg(QString::number(it->id), QString::number(yearTo), QString::number(monthTo), v.sprintf("%d", amount)); EXECUTE_SQL_UPDATE(req, ); } } void Database::ChangePassword(User* user, const QString& password) { QString req; QSqlQuery query(_db); req = QString("UPDATE user SET password=:password WHERE name=:name"); query.prepare(req); query.bindValue(":name", user->_name); query.bindValue(":password", HashPassword(password)); EXECUTE_PREPARED_SQL_UPDATE(); } bool Database::UserExists(const QString& name) { QSqlRecord set; QSqlQuery query(_db); QString req; bool res=false; req = QString("SELECT name FROM user WHERE name=:name"); query.prepare(req); query.bindValue(":name", name); EXECUTE_PREPARED_SQL_QUERY(false); if (query.next()) res = true; else res = false; query.clear(); return res; } void Database::ChangeName(User* user, const QString& name) { QString req; QSqlQuery query(_db); req = QString("UPDATE user SET name=:name WHERE name=:name2"); query.prepare(req); query.bindValue(":name", name); query.bindValue(":name2", user->_name); EXECUTE_PREPARED_SQL_UPDATE(); } void Database::NewUser(const QString& name) { QString req; QSqlQuery query(_db); req = QString("INSERT INTO user ('name', 'password') VALUES (:name, :password)"); query.prepare(req); query.bindValue(":name", name); query.bindValue(":password", HashPassword("")); EXECUTE_PREPARED_SQL_UPDATE(); } /* Shared accounts not currently supported */ void Database::KillMe(User* user) { QString req; std::vector::iterator it; req = QString("DELETE FROM preference WHERE user='%1'").arg(user->_id); EXECUTE_SQL_UPDATE(req, ); if (!user->_accounts.empty()) { for (it = user->_accounts.begin(); it != user->_accounts.end(); it++) DeleteAccount(user, *it, 0); it = user->_accounts.begin(); if (it->is_owner) req = "DELETE FROM operation WHERE account IN('" + QString::number(it->id); else req = "DELETE FROM operation WHERE account IN('-1"; it++; for (;it != user->_accounts.end(); it++) { if (it->is_owner) req += "', '" + QString::number(it->id) ; } req += "')"; req += " OR (user='" + QString::number(user->_id) + "' AND account='')"; EXECUTE_SQL_UPDATE(req, ); } req = QString("DELETE FROM category WHERE user='%1'").arg(user->_id); EXECUTE_SQL_UPDATE(req, ); req = QString("DELETE FROM tag WHERE user='%1'").arg(user->_id); EXECUTE_SQL_UPDATE(req, ); req = QString("DELETE FROM user WHERE id='%1'").arg(user->_id); EXECUTE_SQL_UPDATE(req, ); } void Database::UpdatePreference(User* user, const QString& preference) { QString req; QString value = user->_preferences[preference]; QSqlQuery query(_db); req = "INSERT or REPLACE INTO preference ('user', 'name', 'value') VALUES ('%1', '%2', '%3')" ; req = req.arg(QString::number(user->_id), preference, value); EXECUTE_SQL_UPDATE(req, ); } std::vector* Database::Search(User* user, QString* description, QDate* dateFrom, QDate* dateTo, int* amountFrom, int* amountTo, std::vector categories, int types, std::vector accounts, bool wildcards, std::vector tags) { QSqlRecord set; QSqlQuery query(_db); QString req, v; bool firstCond = false; std::vector::iterator it; std::vector::iterator accountIt; std::vector* res = new std::vector; int i; QString dayFrom, monthFrom, yearFrom; QString dayTo, monthTo, yearTo; QString desc; if (dateFrom) { dayFrom = QString::number(dateFrom->day()-1); monthFrom = QString::number(dateFrom->month()-1); yearFrom = QString::number(dateFrom->year()); } if (dateTo) { dayTo = QString::number(dateTo->day()-1); monthTo = QString::number(dateTo->month()-1); yearTo = QString::number(dateTo->year()); } req = "SELECT * from operation WHERE "; if (description) { desc = *description; ESCAPE_CHARS(desc); if (wildcards) req += "UPPER(description) LIKE UPPER(\"%" + desc + "%\")"; else req += "description=\"" + desc + "\""; firstCond = true; } if (dateFrom) { if (firstCond) req += " AND " ; else firstCond = true; req += "("; req += "year >= " + yearFrom ; req += " AND (month > '" + monthFrom + "' OR (month == '" + monthFrom + "' AND day >= '" + dayFrom + "')"; req += " OR (month < '" + monthFrom + "' AND year > '" + yearFrom + "'))"; req += ")"; } if (dateTo) { if (firstCond) req += " AND " ; else firstCond = true; req += "("; req += "year <= " + yearTo ; req += " AND (month < '" + monthTo + "' OR (month == '" + monthTo + "' AND day <= '" + dayTo + "')"; req += " OR (month > '" + monthTo + "' AND year < '" + yearTo + "'))"; req += ")"; } if (amountFrom) { if (firstCond) req += " AND " ; else firstCond = true; req += "ABS(amount) >= " + v.sprintf("%d", *amountFrom); } if (amountTo) { if (firstCond) req += " AND " ; else firstCond = true; req += "ABS(amount) <= " + v.sprintf("%d", *amountTo); } if (categories.size()) { if (firstCond) req += " AND " ; else firstCond = true; req += "category IN ('"; it = categories.begin(); req += QString::number(*it); it++; for (; it != categories.end(); it++) req += "', '" + QString::number(*it) ; req += "')"; } if (tags.size()) { if (firstCond) req += " AND " ; else firstCond = true; req += "tag IN ('"; it = tags.begin(); req += QString::number(*it); it++; for (; it != tags.end(); it++) req += "', '" + QString::number(*it) ; req += "')"; } if (types) { if (((types & Database::FIX_OP) && !(types & Database::NON_FIX_OP)) || (!(types & Database::FIX_OP) && (types & Database::NON_FIX_OP))) { if (firstCond) req += " AND " ; else firstCond = true; if (types & Database::FIX_OP) req += " fix_cost='1'"; else req += " fix_cost='0'"; } if (((types & Database::CHECKED_OP) && !(types & Database::NOT_CHECKED_OP)) || (!(types & Database::CHECKED_OP) && (types & Database::NOT_CHECKED_OP))) { if (firstCond) req += " AND " ; else firstCond = true; if (types & Database::CHECKED_OP) req += " checked='1'"; else req += " checked='0'"; } } if (firstCond) req += " AND " ; else firstCond = true; if (accounts.size()) { req += "(account IN ('"; it = accounts.begin(); req += QString::number(*it); it++; for (; it != accounts.end(); it++) req += "', '" + QString::number(*it) ; req += "'))"; // req += wxT(" OR user ='") + user->_id + "')"; } else { req += "(account IN ('"; accountIt = user->_accounts.begin(); req += QString::number(accountIt->id); accountIt++; for (;accountIt != user->_accounts.end(); accountIt++) { req += "', '" + QString::number(accountIt->id) ; } req += "')"; req += " OR user ='" + QString::number(user->_id) + "')"; } req += " ORDER BY year " ; req += user->_preferences["operation_order"] ; req += ", month " + user->_preferences["operation_order"] ; req += ", day " + user->_preferences["operation_order"] ; // std::cout << req.toStdString() << "\n"; EXECUTE_SQL_QUERY(req, res); while (query.next()) { Operation op; set = query.record(); fillOperation(&op, set); res->push_back(op); } for(i=0; i < (int)res->size(); i++) if ((*res)[i].parent) user->Group(res, (*res)[i]); return res; } void Database::GetStats(User* user, int monthFrom, int yearFrom, int monthTo, int yearTo, std::map > >* accountAmounts, std::map* categories, std::map* tags) { QSqlRecord set; QSqlQuery query(_db); QString req, req2; std::vector::iterator accountIt; std::vector::iterator categoryIt; std::vector::iterator tagIt; if (!user->_accounts.empty()) { if (accountAmounts) { for (accountIt = user->_accounts.begin(); accountIt != user->_accounts.end(); accountIt++) { req = "SELECT month, year, amount FROM account_amount WHERE account ='" + QString::number(accountIt->id) + "'"; req += " AND (year > '" + QString::number(yearFrom) + "' OR (year == '" + QString::number(yearFrom) + "' AND month >= '" + QString::number(monthFrom) + "'))"; req += " AND (year < '" + QString::number(yearTo) + "' OR (year == '" + QString::number(yearTo) + "' AND month <= '" + QString::number(monthTo) + "'))"; EXECUTE_SQL_QUERY(req, ); while (query.next()) { set = query.record(); (*accountAmounts)[accountIt->id][set.value("year").toInt()][set.value("month").toInt()] = set.value("amount").toInt(); } query.clear(); } } if (categories) { for (categoryIt = user->_categories.begin(); categoryIt != user->_categories.end(); categoryIt++) { if (categoryIt->id == 1) req = "SELECT SUM(amount) as amount FROM operation AS o1 WHERE (category='" + QString::number(categoryIt->id) + "' OR fix_cost='1')"; else req = "SELECT SUM(amount) as amount FROM operation AS o1 WHERE category='" + QString::number(categoryIt->id) + "'"; accountIt = user->_accounts.begin(); req += " AND (account IN('" + QString::number(accountIt->id); accountIt++; for (;accountIt != user->_accounts.end(); accountIt++) { req += "', '" + QString::number(accountIt->id) ; } req += "')"; req += " OR user='" + QString::number(user->_id) + "')"; req += " AND (year > '" + QString::number(yearFrom) + "' OR (year == '" + QString::number(yearFrom) + "' AND month >= '" + QString::number(monthFrom) + "'))"; req += " AND (year < '" + QString::number(yearTo) + "' OR (year == '" + QString::number(yearTo) + "' AND month <= '" + QString::number(monthTo) + "'))"; req += " AND meta='0'"; req2 = req + " AND (transfert='' OR transfert IS 0)"; req2 += " AND amount < 0"; EXECUTE_SQL_QUERY(req2, ); if (query.next()) { set = query.record(); (*categories)[categoryIt->id] = -set.value("amount").toInt(); } query.clear(); // Transfert on blocked accounts must be computed req2 = req + " AND transfert != ''"; req2 += " AND (SELECT blocked FROM account WHERE id=o1.account)"; req2 += " AND amount > 0"; EXECUTE_SQL_QUERY(req2, ); if (query.next()) { set = query.record(); (*categories)[categoryIt->id] += set.value("amount").toInt(); } query.clear(); } } if (tags) { for (tagIt = user->_tags.begin(); tagIt != user->_tags.end(); tagIt++) { req = "SELECT SUM(amount) as amount FROM operation AS o1 WHERE tag='" + QString::number(tagIt->id) + "'"; accountIt = user->_accounts.begin(); req += " AND (account IN('" + QString::number(accountIt->id); accountIt++; for (;accountIt != user->_accounts.end(); accountIt++) { req += "', '" + QString::number(accountIt->id) ; } req += "')"; req += " OR user='" + QString::number(user->_id) + "')"; req += " AND (year > '" + QString::number(yearFrom) + "' OR (year == '" + QString::number(yearFrom) + "' AND month >= '" + QString::number(monthFrom) + "'))"; req += " AND (year < '" + QString::number(yearTo) + "' OR (year == '" + QString::number(yearTo) + "' AND month <= '" + QString::number(monthTo) + "'))"; req += " AND meta='0'"; req2 = req + " AND (transfert='' OR transfert IS 0)"; req2 += " AND amount < 0"; EXECUTE_SQL_QUERY(req2, ); if (query.next()) { set = query.record(); (*tags)[tagIt->id] = -set.value("amount").toInt(); } query.clear(); // Transfert on blocked accounts must be computed req2 = req + " AND transfert != ''"; req2 += " AND (SELECT blocked FROM account WHERE id=o1.account)"; req2 += " AND amount > 0"; EXECUTE_SQL_QUERY(req2, ); if (query.next()) { set = query.record(); (*tags)[tagIt->id] += set.value("amount").toInt(); } query.clear(); } } } } void Database::GetMonthStats(User* user, int month, int year, int nbDays, std::map >* operations, std::map* categories, std::map* tags) { QSqlRecord set; QSqlQuery query(_db); QString req; std::vector::iterator accountIt; int previous_amount, previous_day, cur_day; if (!user->_accounts.empty()) { for (accountIt = user->_accounts.begin(); accountIt != user->_accounts.end(); accountIt++) { req = "SELECT amount FROM account_amount WHERE account ='%1' AND year='%2' AND month='%3'"; req = req.arg(QString::number(accountIt->id), QString::number(year), QString::number(month)); EXECUTE_SQL_QUERY(req, ); while (query.next()) { set = query.record(); (*operations)[accountIt->id].clear(); previous_amount = set.value("amount").toInt(); } query.clear(); req = "SELECT day, amount FROM operation WHERE account='%1' AND year='%2' AND month='%3' AND meta='0' ORDER BY day ASC"; req = req.arg(QString::number(accountIt->id), QString::number(year), QString::number(month)); EXECUTE_SQL_QUERY(req, ); cur_day = previous_day = -1; while (query.next()) { set = query.record(); cur_day = set.value("day").toInt(); while (cur_day != previous_day) { (*operations)[accountIt->id].push_back(previous_amount); previous_day++; } previous_amount += set.value("amount").toInt(); (*operations)[accountIt->id][cur_day] = previous_amount; } query.clear(); while (cur_day < nbDays) { (*operations)[accountIt->id].push_back(previous_amount); cur_day++; } } } // Fill categories GetStats(user, month, year, month, year, 0, categories, tags) ; } std::map* Database::GetNotChecked(User* user, int month, int year) { std::vector::iterator accountIt; std::map* res = new std::map; QSqlRecord set; QSqlQuery query(_db); QString req; for (accountIt = user->_accounts.begin() ;accountIt != user->_accounts.end(); accountIt++) { req = "SELECT SUM(amount) AS amount FROM operation WHERE account='" + QString::number(accountIt->id) + "'"; req += " AND checked='0'"; req += " AND meta='0'"; req += " AND virtual='0'"; req += " AND (year < '" + QString::number(year) + "'" ; req += " OR (year == '" + QString::number(year) + "'" ; req += " AND month < '" + QString::number(month) + "'" ; req += "))"; EXECUTE_SQL_QUERY_WITH_CODE(req, 0, delete res, delete res); if (query.next()) { set = query.record(); (*res)[accountIt->id] = set.value("amount").toInt(); } query.clear(); } return res; } std::map* Database::GetVirtualAmount(User* user, int month, int year) { std::vector::iterator accountIt; std::map* res = new std::map; QSqlRecord set; QSqlQuery query(_db); QString req; for (accountIt = user->_accounts.begin() ;accountIt != user->_accounts.end(); accountIt++) { req = "SELECT SUM(amount) AS amount FROM operation WHERE account='" + QString::number(accountIt->id) + "'"; req += " AND virtual='1'"; req += " AND meta='0'"; req += " AND (year < '" + QString::number(year) + "'" ; req += " OR (year == '" + QString::number(year) + "'" ; req += " AND month < '" + QString::number(month) + "'" ; req += "))"; EXECUTE_SQL_QUERY_WITH_CODE(req, 0, delete res, delete res); if (query.next()) { set = query.record(); (*res)[accountIt->id] = set.value("amount").toInt(); } query.clear(); } return res; } std::map Database::getSharedAccountOwners(int account) { std::map res; QSqlRecord set, set2; QSqlQuery query(_db); QString req, user; req = QString("SELECT user FROM shared_account WHERE account='%1'").arg(account); EXECUTE_SQL_QUERY(req, res); while(query.next()) { set = query.record(); user = set.value("user").toString(); req = QString("SELECT name FROM user WHERE id='%1'").arg(set.value("user").toString()); query.clear(); EXECUTE_SQL_QUERY(req, res); if (query.next()) { set2 = query.record(); res[set2.value("name").toString()] = user; } } return res; } QString Database::getSharedAccountOwner(int account) { QSqlRecord set ; QSqlQuery query(_db); QString req; req = QString("SELECT user FROM account WHERE id='%1'").arg(account); EXECUTE_SQL_QUERY(req, ""); if (query.next()) { set = query.record(); req = QString("SELECT name FROM user WHERE id='%1'").arg(set.value("user").toString()); query.clear(); EXECUTE_SQL_QUERY(req, ""); if (query.next()) { set = query.record(); return set.value("name").toString(); } } return ""; } void Database::UpdateImportPattern(User* user) { std::map::iterator it; QString req, key; QSqlQuery query(_db); for (it = user->_importPatterns.begin(); it != user->_importPatterns.end(); it++) { if (it->second.pattern == ImportEngine::NULL_IMPORT_PATTERN) continue; key = ImportEngine::RemoveUnused(it->first); req = "INSERT or REPLACE INTO import_pattern ('user', 'description', 'pattern', 'account', 'category') VALUES " ; req += "('%1', '%2', '%3', '%4', '%5')"; req = req.arg(QString::number(user->_id), key, it->second.pattern, QString::number(it->second.account), QString::number(it->second.category)); EXECUTE_SQL_UPDATE(req, ); } } void Database::GetHistory(int month, int year, QStringList& list) { QSqlRecord set ; QSqlQuery query(_db); QString req; req = QString("SELECT DISTINCT description AS d FROM operation"); req += " WHERE (year > '" + QString::number(year) + "' OR (year == '" + QString::number(year) + "' AND month >= '" + QString::number(month) + "'))"; req += " ORDER by description"; EXECUTE_SQL_QUERY(req, ); while (query.next()) { set = query.record(); list << set.value("d").toString(); } } bool Database::ChangeDatabase(QString filename) { QString oldFilename = _db.databaseName(); _db.close(); _db.setDatabaseName(filename); if (!_db.open()) { QMessageBox::critical(0, _("Error"), _("Unable to open database")); _db.setDatabaseName(oldFilename); _db.open(); return false; } try { CheckDatabaseVersion(); } catch(...) { _db.setDatabaseName(oldFilename); _db.open(); return false; } return true; }