From 50cadf3dac0d56ef8181d1800cc30f8dcb749141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 13 Jun 2017 10:38:39 +0200 Subject: Implement our own database ORM, and update the whole code to use it Entirely replace LiteSQL fix #3271 --- src/database/database.cpp | 204 ++++++++++++++++++++++------------------------ 1 file changed, 97 insertions(+), 107 deletions(-) (limited to 'src/database/database.cpp') diff --git a/src/database/database.cpp b/src/database/database.cpp index 9f310da..1738a69 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -2,175 +2,166 @@ #ifdef USE_DATABASE #include -#include -#include #include #include #include -using namespace std::string_literals; +#include -std::unique_ptr Database::db; +sqlite3* Database::db; +Database::MucLogLineTable Database::muc_log_lines("MucLogLine_"); +Database::GlobalOptionsTable Database::global_options("GlobalOptions_"); +Database::IrcServerOptionsTable Database::irc_server_options("IrcServerOptions_"); +Database::IrcChannelOptionsTable Database::irc_channel_options("IrcChannelOptions_"); -void Database::open(const std::string& filename, const std::string& db_type) +void Database::open(const std::string& filename) { - try - { - auto new_db = std::make_unique(db_type, - "database="s + filename); - if (new_db->needsUpgrade()) - new_db->upgrade(); - Database::db = std::move(new_db); - } catch (const litesql::DatabaseError& e) { - log_error("Failed to open database ", filename, ". ", e.what()); - throw; - } + auto res = sqlite3_open_v2(filename.data(), &Database::db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr); + log_debug("open: ", res); + Database::muc_log_lines.create(Database::db); + Database::global_options.create(Database::db); + Database::irc_server_options.create(Database::db); + Database::irc_channel_options.create(Database::db); } -void Database::set_verbose(const bool val) -{ - Database::db->verbose = val; -} -db::GlobalOptions Database::get_global_options(const std::string& owner) +Database::GlobalOptions Database::get_global_options(const std::string& owner) { - try { - auto options = litesql::select(*Database::db, - db::GlobalOptions::Owner == owner).one(); - return options; - } catch (const litesql::NotFound& e) { - db::GlobalOptions options(*Database::db); - options.owner = owner; - return options; - } + auto request = Database::global_options.select().where() << Owner{} << "=" << owner; + + Database::GlobalOptions options{Database::global_options.get_name()}; + auto result = request.execute(Database::db); + if (result.size() == 1) + options = result.front(); + else + options.col() = owner; + return options; } -db::IrcServerOptions Database::get_irc_server_options(const std::string& owner, - const std::string& server) +Database::IrcServerOptions Database::get_irc_server_options(const std::string& owner, const std::string& server) { - try { - auto options = litesql::select(*Database::db, - db::IrcServerOptions::Owner == owner && - db::IrcServerOptions::Server == server).one(); - return options; - } catch (const litesql::NotFound& e) { - db::IrcServerOptions options(*Database::db); - options.owner = owner; - options.server = server; - // options.update(); - return options; - } + auto request = Database::irc_server_options.select().where() << Owner{} << "=" << owner << " and " << Server{} << "=" << server; + + Database::IrcServerOptions options{Database::irc_server_options.get_name()}; + auto result = request.execute(Database::db); + if (result.size() == 1) + options = result.front(); + else + { + options.col() = owner; + options.col() = server; + } + return options; } -db::IrcChannelOptions Database::get_irc_channel_options(const std::string& owner, - const std::string& server, - const std::string& channel) +Database::IrcChannelOptions Database::get_irc_channel_options(const std::string& owner, const std::string& server, const std::string& channel) { - try { - auto options = litesql::select(*Database::db, - db::IrcChannelOptions::Owner == owner && - db::IrcChannelOptions::Server == server && - db::IrcChannelOptions::Channel == channel).one(); - return options; - } catch (const litesql::NotFound& e) { - db::IrcChannelOptions options(*Database::db); - options.owner = owner; - options.server = server; - options.channel = channel; - return options; - } + auto request = Database::irc_channel_options.select().where() << Owner{} << "=" << owner <<\ + " and " << Server{} << "=" << server <<\ + " and " << Channel{} << "=" << channel; + Database::IrcChannelOptions options{Database::irc_channel_options.get_name()}; + auto result = request.execute(Database::db); + if (result.size() == 1) + options = result.front(); + else + { + options.col() = owner; + options.col() = server; + options.col() = channel; + } + return options; } -db::IrcChannelOptions Database::get_irc_channel_options_with_server_default(const std::string& owner, - const std::string& server, - const std::string& channel) +Database::IrcChannelOptions Database::get_irc_channel_options_with_server_default(const std::string& owner, const std::string& server, + const std::string& channel) { auto coptions = Database::get_irc_channel_options(owner, server, channel); auto soptions = Database::get_irc_server_options(owner, server); - coptions.encodingIn = get_first_non_empty(coptions.encodingIn.value(), - soptions.encodingIn.value()); - coptions.encodingOut = get_first_non_empty(coptions.encodingOut.value(), - soptions.encodingOut.value()); + coptions.col() = get_first_non_empty(coptions.col(), + soptions.col()); + coptions.col() = get_first_non_empty(coptions.col(), + soptions.col()); - coptions.maxHistoryLength = get_first_non_empty(coptions.maxHistoryLength.value(), - soptions.maxHistoryLength.value()); + coptions.col() = get_first_non_empty(coptions.col(), + soptions.col()); return coptions; } -db::IrcChannelOptions Database::get_irc_channel_options_with_server_and_global_default(const std::string& owner, - const std::string& server, - const std::string& channel) +Database::IrcChannelOptions Database::get_irc_channel_options_with_server_and_global_default(const std::string& owner, const std::string& server, const std::string& channel) { auto coptions = Database::get_irc_channel_options(owner, server, channel); auto soptions = Database::get_irc_server_options(owner, server); auto goptions = Database::get_global_options(owner); - coptions.encodingIn = get_first_non_empty(coptions.encodingIn.value(), - soptions.encodingIn.value()); - coptions.encodingOut = get_first_non_empty(coptions.encodingOut.value(), - soptions.encodingOut.value()); + coptions.col() = get_first_non_empty(coptions.col(), + soptions.col()); - coptions.maxHistoryLength = get_first_non_empty(coptions.maxHistoryLength.value(), - soptions.maxHistoryLength.value(), - goptions.maxHistoryLength.value()); + coptions.col() = get_first_non_empty(coptions.col(), + soptions.col()); + + coptions.col() = get_first_non_empty(coptions.col(), + soptions.col(), + goptions.col()); return coptions; } -std::string Database::store_muc_message(const std::string& owner, const Iid& iid, - Database::time_point date, - const std::string& body, - const std::string& nick) +std::string Database::store_muc_message(const std::string& owner, const std::string& chan_name, + const std::string& server_name, Database::time_point date, + const std::string& body, const std::string& nick) { - db::MucLogLine line(*Database::db); + auto line = Database::muc_log_lines.row(); auto uuid = Database::gen_uuid(); - line.uuid = uuid; - line.owner = owner; - line.ircChanName = iid.get_local(); - line.ircServerName = iid.get_server(); - line.date = std::chrono::duration_cast(date.time_since_epoch()).count(); - line.body = body; - line.nick = nick; + line.col() = uuid; + line.col() = owner; + line.col() = chan_name; + line.col() = server_name; + line.col() = std::chrono::duration_cast(date.time_since_epoch()).count(); + line.col() = body; + line.col() = nick; - line.update(); + line.save(Database::db); return uuid; } -std::vector Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, +std::vector Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, int limit, const std::string& start, const std::string& end) { - auto request = litesql::select(*Database::db, - db::MucLogLine::Owner == owner && - db::MucLogLine::IrcChanName == chan_name && - db::MucLogLine::IrcServerName == server); - request.orderBy(db::MucLogLine::Id, false); + auto request = Database::muc_log_lines.select().where() << Database::Owner{} << "=" << owner << \ + " and " << Database::IrcChanName{} << "=" << chan_name << \ + " and " << Database::IrcServerName{} << "=" << server; - if (limit >= 0) - request.limit(limit); if (!start.empty()) { const auto start_time = utils::parse_datetime(start); if (start_time != -1) - request.where(db::MucLogLine::Date >= start_time); + request << " and " << Database::Date{} << ">=" << start_time; } if (!end.empty()) { const auto end_time = utils::parse_datetime(end); if (end_time != -1) - request.where(db::MucLogLine::Date <= end_time); + request << " and " << Database::Date{} << "<=" << end_time; } - const auto& res = request.all(); - return {res.crbegin(), res.crend()}; + + request.order_by() << Id{} << " DESC "; + + if (limit >= 0) + request.limit() << limit; + + auto result = request.execute(Database::db); + + return {result.crbegin(), result.crend()}; } void Database::close() { - Database::db.reset(nullptr); + sqlite3_close_v2(Database::db); } std::string Database::gen_uuid() @@ -182,5 +173,4 @@ std::string Database::gen_uuid() return uuid_str; } - -#endif +#endif \ No newline at end of file -- cgit v1.2.3 From 4a963cc480bb5a78e20380131ba886a7a23b0782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 16 Jun 2017 09:49:08 +0200 Subject: At startup, upgrade all database tables by adding missing columns --- src/database/database.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/database/database.cpp') diff --git a/src/database/database.cpp b/src/database/database.cpp index 1738a69..cb41070 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -19,9 +19,13 @@ void Database::open(const std::string& filename) auto res = sqlite3_open_v2(filename.data(), &Database::db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr); log_debug("open: ", res); Database::muc_log_lines.create(Database::db); + Database::muc_log_lines.upgrade(Database::db); Database::global_options.create(Database::db); + Database::global_options.upgrade(Database::db); Database::irc_server_options.create(Database::db); + Database::irc_server_options.upgrade(Database::db); Database::irc_channel_options.create(Database::db); + Database::irc_channel_options.upgrade(Database::db); } -- cgit v1.2.3 From 4d55a120d8fa5564a439102ab97b43da589bf4f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 21 Jun 2017 17:36:53 +0200 Subject: Re-implement correctly the handling of failure to open the database MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we can’t open it at startup, we exit. If we can’t open it on reload, we keep the previously-opened database. This way, we’re assured to always have a valid and open database available. --- src/database/database.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src/database/database.cpp') diff --git a/src/database/database.cpp b/src/database/database.cpp index cb41070..ba69d39 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -16,8 +16,18 @@ Database::IrcChannelOptionsTable Database::irc_channel_options("IrcChannelOption void Database::open(const std::string& filename) { - auto res = sqlite3_open_v2(filename.data(), &Database::db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr); - log_debug("open: ", res); + // Try to open the specified database. + // Close and replace the previous database pointer if it succeeded. If it did + // not, just leave things untouched + sqlite3* new_db; + auto res = sqlite3_open_v2(filename.data(), &new_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr); + if (res != SQLITE_OK) + { + log_error("Failed to open database file ", filename, ": ", sqlite3_errmsg(Database::db)); + throw std::runtime_error(""); + } + Database::close(); + Database::db = new_db; Database::muc_log_lines.create(Database::db); Database::muc_log_lines.upgrade(Database::db); Database::global_options.create(Database::db); -- cgit v1.2.3 From 8a7166eef9d46ec15850cadb674edb2873cebecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 22 Jun 2017 16:14:00 +0200 Subject: Set the database pointer to nullptr after a close --- src/database/database.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/database/database.cpp') diff --git a/src/database/database.cpp b/src/database/database.cpp index ba69d39..246cdbc 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -176,6 +176,7 @@ std::vector Database::get_muc_logs(const std::string& owne void Database::close() { sqlite3_close_v2(Database::db); + Database::db = nullptr; } std::string Database::gen_uuid() -- cgit v1.2.3 From b71ca15a0f9114db38eec23b49d1489a2ff1d0ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 23 Jun 2017 00:11:07 +0200 Subject: Move a few functions from select_query to query --- src/database/database.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'src/database/database.cpp') diff --git a/src/database/database.cpp b/src/database/database.cpp index 246cdbc..92f7682 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -41,7 +41,8 @@ void Database::open(const std::string& filename) Database::GlobalOptions Database::get_global_options(const std::string& owner) { - auto request = Database::global_options.select().where() << Owner{} << "=" << owner; + auto request = Database::global_options.select(); + request.where() << Owner{} << "=" << owner; Database::GlobalOptions options{Database::global_options.get_name()}; auto result = request.execute(Database::db); @@ -54,7 +55,8 @@ Database::GlobalOptions Database::get_global_options(const std::string& owner) Database::IrcServerOptions Database::get_irc_server_options(const std::string& owner, const std::string& server) { - auto request = Database::irc_server_options.select().where() << Owner{} << "=" << owner << " and " << Server{} << "=" << server; + auto request = Database::irc_server_options.select(); + request.where() << Owner{} << "=" << owner << " and " << Server{} << "=" << server; Database::IrcServerOptions options{Database::irc_server_options.get_name()}; auto result = request.execute(Database::db); @@ -70,9 +72,10 @@ Database::IrcServerOptions Database::get_irc_server_options(const std::string& o Database::IrcChannelOptions Database::get_irc_channel_options(const std::string& owner, const std::string& server, const std::string& channel) { - auto request = Database::irc_channel_options.select().where() << Owner{} << "=" << owner <<\ - " and " << Server{} << "=" << server <<\ - " and " << Channel{} << "=" << channel; + auto request = Database::irc_channel_options.select(); + request.where() << Owner{} << "=" << owner <<\ + " and " << Server{} << "=" << server <<\ + " and " << Channel{} << "=" << channel; Database::IrcChannelOptions options{Database::irc_channel_options.get_name()}; auto result = request.execute(Database::db); if (result.size() == 1) @@ -146,9 +149,10 @@ std::string Database::store_muc_message(const std::string& owner, const std::str std::vector Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, int limit, const std::string& start, const std::string& end) { - auto request = Database::muc_log_lines.select().where() << Database::Owner{} << "=" << owner << \ - " and " << Database::IrcChanName{} << "=" << chan_name << \ - " and " << Database::IrcServerName{} << "=" << server; + auto request = Database::muc_log_lines.select(); + request.where() << Database::Owner{} << "=" << owner << \ + " and " << Database::IrcChanName{} << "=" << chan_name << \ + " and " << Database::IrcServerName{} << "=" << server; if (!start.empty()) { -- cgit v1.2.3