diff --git a/src/mysqlbackend.cpp b/src/mysqlbackend.cpp index 0bad7c6378d9f0fcb38e0b5392d92204aa223028..a10d89ec7ec82b49e4df5edae5cd61fdaf642342 100644 --- a/src/mysqlbackend.cpp +++ b/src/mysqlbackend.cpp @@ -29,7 +29,7 @@ using namespace log4cxx; #define MYSQL_DB_VERSION 2 #define CHECK_DB_RESPONSE(stmt) \ if(stmt) { \ - sqlite3_exec(m_db, "ROLLBACK;", NULL, NULL, NULL); \ + sqlite3_EXEC(m_db, "ROLLBACK;", NULL, NULL, NULL); \ return 0; \ } @@ -72,11 +72,27 @@ using namespace log4cxx; LOG4CXX_ERROR(logger, NAME << " " << mysql_error(&m_conn)); \ } +#define EXEC(STMT, METHOD) \ + {\ + int ret = STMT->execute(); \ + if (ret == 0) \ + exec_ok = true; \ + else if (ret == 2013) { \ + LOG4CXX_INFO(logger, "MySQL connection lost. Reconnecting...");\ + disconnect(); \ + connect(); \ + return METHOD; \ + } \ + else \ + exec_ok = false; \ + } + using namespace boost; namespace Transport { static LoggerPtr logger = Logger::getLogger("MySQLBackend"); +static bool exec_ok; MySQLBackend::Statement::Statement(MYSQL *conn, const std::string &format, const std::string &statement) { m_resultOffset = -1; @@ -184,7 +200,7 @@ MySQLBackend::Statement::~Statement() { FINALIZE_STMT(m_stmt); } -bool MySQLBackend::Statement::execute() { +int MySQLBackend::Statement::execute() { // If statement has some input and doesn't have any output, we have // to clear the offset now, because operator>> will not be called. m_offset = 0; @@ -193,9 +209,9 @@ bool MySQLBackend::Statement::execute() { if ((ret = mysql_stmt_execute(m_stmt)) != 0) { LOG4CXX_ERROR(logger, m_string << " " << mysql_stmt_error(m_stmt) << "; " << mysql_error(m_conn)); - return false; + return mysql_stmt_errno(m_stmt); } - return true; + return 0; } int MySQLBackend::Statement::fetch() { @@ -256,13 +272,18 @@ MySQLBackend::Statement& MySQLBackend::Statement::operator >> (std::string& t) { MySQLBackend::MySQLBackend(Config *config) { m_config = config; + m_prefix = CONFIG_STRING(m_config, "database.prefix"); mysql_init(&m_conn); my_bool my_true = 1; mysql_options(&m_conn, MYSQL_OPT_RECONNECT, &my_true); - m_prefix = CONFIG_STRING(m_config, "database.prefix"); } MySQLBackend::~MySQLBackend(){ + disconnect(); +} + +void MySQLBackend::disconnect() { + LOG4CXX_INFO(logger, "Disconnecting"); delete m_setUser; delete m_getUser; delete m_removeUser; @@ -286,7 +307,7 @@ bool MySQLBackend::connect() { CONFIG_STRING(m_config, "database.user") << ", database " << CONFIG_STRING(m_config, "database.database") << ", port " << CONFIG_INT(m_config, "database.port") ); - + if (!mysql_real_connect(&m_conn, CONFIG_STRING(m_config, "database.server").c_str(), CONFIG_STRING(m_config, "database.user").c_str(), CONFIG_STRING(m_config, "database.password").c_str(), @@ -389,12 +410,13 @@ bool MySQLBackend::exec(const std::string &query) { void MySQLBackend::setUser(const UserInfo &user) { *m_setUser << user.jid << user.uin << user.password << user.language << user.encoding << user.vip << user.password; - m_setUser->execute(); + EXEC(m_setUser, setUser(user)); } bool MySQLBackend::getUser(const std::string &barejid, UserInfo &user) { *m_getUser << barejid; - if (!m_getUser->execute()) + EXEC(m_getUser, getUser(barejid, user)); + if (!exec_ok) return false; int ret = false; @@ -408,7 +430,7 @@ bool MySQLBackend::getUser(const std::string &barejid, UserInfo &user) { void MySQLBackend::setUserOnline(long id, bool online) { *m_setUserOnline << online << id; - m_setUserOnline->execute(); + EXEC(m_setUserOnline, setUserOnline(id, online)); } long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { @@ -417,14 +439,14 @@ long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { *m_addBuddy << (buddyInfo.groups.size() == 0 ? "" : buddyInfo.groups[0]); *m_addBuddy << buddyInfo.alias << buddyInfo.flags; - m_addBuddy->execute(); + EXEC(m_addBuddy, addBuddy(userId, buddyInfo)); long id = (long) mysql_insert_id(&m_conn); // INSERT OR REPLACE INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES (?, ?, ?, ?, ?) if (!buddyInfo.settings.find("icon_hash")->second.s.empty()) { *m_updateBuddySetting << userId << id << buddyInfo.settings.find("icon_hash")->first << (int) TYPE_STRING << buddyInfo.settings.find("icon_hash")->second.s << buddyInfo.settings.find("icon_hash")->second.s; - m_updateBuddySetting->execute(); + EXEC(m_updateBuddySetting, addBuddy(userId, buddyInfo)); } return id; @@ -436,7 +458,7 @@ void MySQLBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { *m_updateBuddy << buddyInfo.alias << buddyInfo.flags << buddyInfo.subscription; *m_updateBuddy << userId << buddyInfo.legacyName; - m_updateBuddy->execute(); + EXEC(m_updateBuddy, updateBuddy(userId, buddyInfo)); } bool MySQLBackend::getBuddies(long id, std::list &roster) { @@ -450,7 +472,8 @@ bool MySQLBackend::getBuddies(long id, std::list &roster) { long buddy_id = -1; std::string key; - if (!m_getBuddies->execute()) + EXEC(m_getBuddies, getBuddies(id, roster)); + if (!exec_ok) return false; while (m_getBuddies->fetch() == 0) { @@ -465,7 +488,8 @@ bool MySQLBackend::getBuddies(long id, std::list &roster) { roster.push_back(b); } - if (!m_getBuddiesSettings->execute()) + EXEC(m_getBuddiesSettings, getBuddies(id, roster)); + if (!exec_ok) return false; BOOST_FOREACH(BuddyInfo &b, roster) { @@ -511,19 +535,23 @@ bool MySQLBackend::getBuddies(long id, std::list &roster) { bool MySQLBackend::removeUser(long id) { *m_removeUser << (int) id; - if (!m_removeUser->execute()) + EXEC(m_removeUser, removeUser(id)); + if (!exec_ok) return false; *m_removeUserSettings << (int) id; - if (!m_removeUserSettings->execute()) + EXEC(m_removeUserSettings, removeUser(id)); + if (!exec_ok) return false; *m_removeUserBuddies << (int) id; - if (!m_removeUserBuddies->execute()) + EXEC(m_removeUserBuddies, removeUser(id)); + if (!exec_ok) return false; *m_removeUserBuddiesSettings << (int) id; - if (!m_removeUserBuddiesSettings->execute()) + EXEC(m_removeUserBuddiesSettings, removeUser(id)); + if (!exec_ok) return false; return true; @@ -532,11 +560,11 @@ bool MySQLBackend::removeUser(long id) { void MySQLBackend::getUserSetting(long id, const std::string &variable, int &type, std::string &value) { // "SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=? AND var=?" *m_getUserSetting << id << variable; - m_getUserSetting->execute(); + EXEC(m_getUserSetting, getUserSetting(id, variable, type, value)); if (m_getUserSetting->fetch() != 0) { // "INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES (?,?,?,?)" *m_setUserSetting << id << variable << type << value; - m_setUserSetting->execute(); + EXEC(m_setUserSetting, getUserSetting(id, variable, type, value)); } else { *m_getUserSetting >> type >> value; @@ -546,7 +574,7 @@ void MySQLBackend::getUserSetting(long id, const std::string &variable, int &typ void MySQLBackend::updateUserSetting(long id, const std::string &variable, const std::string &value) { // "UPDATE " + m_prefix + "users_settings SET value=? WHERE user_id=? AND var=?" *m_updateUserSetting << value << id << variable; - m_updateUserSetting->execute(); + EXEC(m_updateUserSetting, updateUserSetting(id, variable, value)); } void MySQLBackend::beginTransaction() {