From 409eda21a4287078d209e05ac37ed0c8fa57573a Mon Sep 17 00:00:00 2001 From: loonycyborg Date: Mon, 6 Feb 2017 15:43:41 +0300 Subject: [PATCH] Reimplement autoreconnect if sql server lost functionality --- src/server/forum_user_handler.cpp | 28 ++++++++++++++++++++++------ src/server/forum_user_handler.hpp | 2 ++ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/server/forum_user_handler.cpp b/src/server/forum_user_handler.cpp index a42c9313fe79..6ccf29528fea 100644 --- a/src/server/forum_user_handler.cpp +++ b/src/server/forum_user_handler.cpp @@ -116,7 +116,7 @@ bool fuh::user_exists(const std::string& name) { // Make a test query for this username try { - return prepared_statement(conn, "SELECT 1 FROM `" + db_users_table_ + "` WHERE UPPER(username)=UPPER(?)", name); + return prepared_statement("SELECT 1 FROM `" + db_users_table_ + "` WHERE UPPER(username)=UPPER(?)", name); } catch (sql_error& e) { ERR_UH << "Could not execute test query for user '" << name << "' :" << e.message << std::endl; // If the database is down just let all usernames log in @@ -246,9 +246,25 @@ void fuh::set_lastlogin(const std::string& user, const time_t& lastlogin) { } } +template +inline T fuh::prepared_statement(const std::string& sql, Args&&... args) +{ + try { + return ::prepared_statement(conn, sql, std::forward(args)...); + } catch (sql_error&) { + WRN_UH << "caught sql error, trying to reconnect and retry..." << std::endl; + //Try to reconnect and execute query again + if(!mysql_real_connect(conn, db_host_.c_str(), db_user_.c_str(), db_password_.c_str(), db_name_.c_str(), 0, nullptr, 0)) { + ERR_UH << "Could not connect to database: " << mysql_errno(conn) << ": " << mysql_error(conn) << std::endl; + throw sql_error("Error querying database."); + } + } + return ::prepared_statement(conn, sql, std::forward(args)...); +} + template T fuh::get_detail_for_user(const std::string& name, const std::string& detail) { - return prepared_statement(conn, + return prepared_statement( "SELECT `" + detail + "` FROM `" + db_users_table_ + "` WHERE UPPER(username)=UPPER(?)", name); } @@ -256,7 +272,7 @@ T fuh::get_detail_for_user(const std::string& name, const std::string& detail) { template T fuh::get_writable_detail_for_user(const std::string& name, const std::string& detail) { if(!extra_row_exists(name)) throw sql_error("row doesn't exist"); - return prepared_statement(conn, + return prepared_statement( "SELECT `" + detail + "` FROM `" + db_extra_table_ + "` WHERE UPPER(username)=UPPER(?)", name); } @@ -267,9 +283,9 @@ void fuh::write_detail(const std::string& name, const std::string& detail, T&& v // Check if we do already have a row for this user in the extra table if(!extra_row_exists(name)) { // If not create the row - prepared_statement(conn, "INSERT INTO `" + db_extra_table_ + "` VALUES(?,?,'0')", name, std::forward(value)); + prepared_statement("INSERT INTO `" + db_extra_table_ + "` VALUES(?,?,'0')", name, std::forward(value)); } - prepared_statement(conn, "UPDATE `" + db_extra_table_ + "` SET " + detail + "=? WHERE UPPER(username)=UPPER(?)", std::forward(value), name); + prepared_statement("UPDATE `" + db_extra_table_ + "` SET " + detail + "=? WHERE UPPER(username)=UPPER(?)", std::forward(value), name); } catch (sql_error& e) { ERR_UH << "Could not set detail for user '" << name << "': " << e.message << std::endl; } @@ -279,7 +295,7 @@ bool fuh::extra_row_exists(const std::string& name) { // Make a test query for this username try { - return prepared_statement(conn, "SELECT 1 FROM `" + db_extra_table_ + "` WHERE UPPER(username)=UPPER(?)", name); + return prepared_statement("SELECT 1 FROM `" + db_extra_table_ + "` WHERE UPPER(username)=UPPER(?)", name); } catch (sql_error& e) { ERR_UH << "Could not execute test query for user '" << name << "' :" << e.message << std::endl; return false; diff --git a/src/server/forum_user_handler.hpp b/src/server/forum_user_handler.hpp index bdb96ef8cc6a..ea2580115692 100644 --- a/src/server/forum_user_handler.hpp +++ b/src/server/forum_user_handler.hpp @@ -98,6 +98,8 @@ class fuh : public user_handler { MYSQL *conn; + template + inline T prepared_statement(const std::string& sql, Args&&...); // Query a detail for a particular user from the database template T get_detail_for_user(const std::string& name, const std::string& detail);