diff --git a/src/db/Marriage.cpp b/src/db/Marriage.cpp index ee4b15b..a280ac2 100644 --- a/src/db/Marriage.cpp +++ b/src/db/Marriage.cpp @@ -3,9 +3,177 @@ #include "Main.h" #include "DBManager.h" #include "ClientManager.h" +#include "libsql/Statement.h" + +#include +#include namespace marriage { + namespace + { + struct MarriageRow + { + DWORD pid1 = 0; + DWORD pid2 = 0; + int lovePoint = 0; + DWORD time = 0; + BYTE isMarried = 0; + char name1[CHARACTER_NAME_MAX_LEN + 1] = {}; + char name2[CHARACTER_NAME_MAX_LEN + 1] = {}; + }; + + bool PrepareMarriageStmt(CStmt& stmt, const std::string& query) + { + CAsyncSQL* sql = CDBManager::instance().GetDirectSQL(SQL_PLAYER); + + if (!sql) + { + sys_err("player SQL handle is not initialized"); + return false; + } + + return stmt.Prepare(sql, query.c_str()); + } + + bool PurgePendingMarriages() + { + CStmt stmt; + const std::string query = "DELETE FROM marriage WHERE is_married = 0"; + + if (!PrepareMarriageStmt(stmt, query)) + return false; + + return stmt.Execute(); + } + + bool LoadMarriageRows(std::vector& rows) + { + CStmt stmt; + MarriageRow row = {}; + const std::string query = std::string("SELECT pid1, pid2, love_point, time, is_married, p1.name, p2.name FROM marriage, player") + + GetTablePostfix() + " as p1, player" + GetTablePostfix() + " as p2 WHERE p1.id = pid1 AND p2.id = pid2"; + + rows.clear(); + + if (!PrepareMarriageStmt(stmt, query)) + return false; + + if (!stmt.BindResult(MYSQL_TYPE_LONG, &row.pid1) + || !stmt.BindResult(MYSQL_TYPE_LONG, &row.pid2) + || !stmt.BindResult(MYSQL_TYPE_LONG, &row.lovePoint) + || !stmt.BindResult(MYSQL_TYPE_LONG, &row.time) + || !stmt.BindResult(MYSQL_TYPE_TINY, &row.isMarried) + || !stmt.BindResult(MYSQL_TYPE_STRING, row.name1, sizeof(row.name1)) + || !stmt.BindResult(MYSQL_TYPE_STRING, row.name2, sizeof(row.name2))) + { + return false; + } + + if (!stmt.Execute()) + return false; + + rows.reserve(stmt.iRows); + + for (int i = 0; i < stmt.iRows; ++i) + { + row = {}; + + if (!stmt.Fetch()) + return false; + + size_t name1Len = stmt.GetResultLength(5); + if (name1Len >= sizeof(row.name1)) + name1Len = sizeof(row.name1) - 1; + row.name1[name1Len] = '\0'; + + size_t name2Len = stmt.GetResultLength(6); + if (name2Len >= sizeof(row.name2)) + name2Len = sizeof(row.name2) - 1; + row.name2[name2Len] = '\0'; + + rows.push_back(row); + } + + return true; + } + + bool AddMarriageRow(DWORD pid1, DWORD pid2, DWORD time) + { + CStmt stmt; + const std::string query = "INSERT INTO marriage(pid1, pid2, love_point, time) VALUES (?, ?, 0, ?)"; + + if (!PrepareMarriageStmt(stmt, query)) + return false; + + if (!stmt.BindParam(MYSQL_TYPE_LONG, &pid1) + || !stmt.BindParam(MYSQL_TYPE_LONG, &pid2) + || !stmt.BindParam(MYSQL_TYPE_LONG, &time) + || !stmt.Execute()) + { + return false; + } + + return stmt.GetAffectedRows() != 0 && stmt.GetAffectedRows() != static_cast(-1); + } + + bool UpdateMarriageRow(DWORD pid1, DWORD pid2, int lovePoint, BYTE isMarried) + { + CStmt stmt; + const std::string query = "UPDATE marriage SET love_point = ?, is_married = ? WHERE pid1 = ? AND pid2 = ?"; + + if (!PrepareMarriageStmt(stmt, query)) + return false; + + if (!stmt.BindParam(MYSQL_TYPE_LONG, &lovePoint) + || !stmt.BindParam(MYSQL_TYPE_TINY, &isMarried) + || !stmt.BindParam(MYSQL_TYPE_LONG, &pid1) + || !stmt.BindParam(MYSQL_TYPE_LONG, &pid2) + || !stmt.Execute()) + { + return false; + } + + return stmt.GetAffectedRows() != 0 && stmt.GetAffectedRows() != static_cast(-1); + } + + bool RemoveMarriageRow(DWORD pid1, DWORD pid2) + { + CStmt stmt; + const std::string query = "DELETE FROM marriage WHERE pid1 = ? AND pid2 = ?"; + + if (!PrepareMarriageStmt(stmt, query)) + return false; + + if (!stmt.BindParam(MYSQL_TYPE_LONG, &pid1) + || !stmt.BindParam(MYSQL_TYPE_LONG, &pid2) + || !stmt.Execute()) + { + return false; + } + + return stmt.GetAffectedRows() != 0 && stmt.GetAffectedRows() != static_cast(-1); + } + + bool MarkMarriageAsMarried(DWORD pid1, DWORD pid2) + { + CStmt stmt; + const std::string query = "UPDATE marriage SET is_married = 1 WHERE pid1 = ? AND pid2 = ?"; + + if (!PrepareMarriageStmt(stmt, query)) + return false; + + if (!stmt.BindParam(MYSQL_TYPE_LONG, &pid1) + || !stmt.BindParam(MYSQL_TYPE_LONG, &pid2) + || !stmt.Execute()) + { + return false; + } + + return stmt.GetAffectedRows() != 0 && stmt.GetAffectedRows() != static_cast(-1); + } + } + const DWORD WEDDING_LENGTH = 60 * 60; // sec bool operator < (const TWedding& lhs, const TWedding& rhs) { @@ -34,38 +202,29 @@ namespace marriage bool CManager::Initialize() { - char szQuery[1024]; + std::vector rows; - snprintf(szQuery, sizeof(szQuery), - "SELECT pid1, pid2, love_point, time, is_married, p1.name, p2.name FROM marriage, player%s as p1, player%s as p2 WHERE p1.id = pid1 AND p2.id = pid2", - GetTablePostfix(), GetTablePostfix()); + if (!PurgePendingMarriages()) + sys_err("failed to purge pending marriages"); - CDBManager::instance().DirectQuery("DELETE FROM marriage WHERE is_married = 0"); - - auto pmsg = CDBManager::instance().DirectQuery(szQuery); - SQLResult * pRes = pmsg->Get(); - sys_log(0, "MarriageList(size=%lu)", pRes->uiNumRows); + if (!LoadMarriageRows(rows)) + return false; - if (pRes->uiNumRows > 0) + sys_log(0, "MarriageList(size=%lu)", rows.size()); + + if (!rows.empty()) { - for (uint uiRow = 0; uiRow != pRes->uiNumRows; ++uiRow) + for (size_t uiRow = 0; uiRow != rows.size(); ++uiRow) { - MYSQL_ROW row = mysql_fetch_row(pRes->pSQLResult); + const auto& row = rows[uiRow]; - DWORD pid1 = 0; str_to_number(pid1, row[0]); - DWORD pid2 = 0; str_to_number(pid2, row[1]); - int love_point = 0; str_to_number(love_point, row[2]); - DWORD time = 0; str_to_number(time, row[3]); - BYTE is_married = 0; str_to_number(is_married, row[4]); - const char* name1 = row[5]; - const char* name2 = row[6]; - - TMarriage* pMarriage = new TMarriage(pid1, pid2, love_point, time, is_married, name1, name2); + TMarriage* pMarriage = new TMarriage(row.pid1, row.pid2, row.lovePoint, row.time, row.isMarried, row.name1, row.name2); m_Marriages.insert(pMarriage); - m_MarriageByPID.insert(make_pair(pid1, pMarriage)); - m_MarriageByPID.insert(make_pair(pid2, pMarriage)); + m_MarriageByPID.insert(make_pair(row.pid1, pMarriage)); + m_MarriageByPID.insert(make_pair(row.pid2, pMarriage)); - sys_log(0, "Marriage %lu: LP:%d TM:%u ST:%d %10lu:%16s %10lu:%16s ", uiRow, love_point, time, is_married, pid1, name1, pid2, name2); + sys_log(0, "Marriage %lu: LP:%d TM:%u ST:%d %10lu:%16s %10lu:%16s ", + static_cast(uiRow), row.lovePoint, row.time, row.isMarried, row.pid1, row.name1, row.pid2, row.name2); } } return true; @@ -98,13 +257,7 @@ namespace marriage Align(dwPID1, dwPID2); - char szQuery[512]; - snprintf(szQuery, sizeof(szQuery), "INSERT INTO marriage(pid1, pid2, love_point, time) VALUES (%u, %u, 0, %u)", dwPID1, dwPID2, now); - - auto pmsg = CDBManager::instance().DirectQuery(szQuery); - - SQLResult* res = pmsg->Get(); - if (res->uiAffectedRows == 0 || res->uiAffectedRows == (uint32_t)-1) + if (!AddMarriageRow(dwPID1, dwPID2, now)) { sys_err("cannot insert marriage"); return; @@ -137,14 +290,7 @@ namespace marriage Align(dwPID1, dwPID2); - char szQuery[512]; - snprintf(szQuery, sizeof(szQuery), "UPDATE marriage SET love_point = %d, is_married = %d WHERE pid1 = %u AND pid2 = %u", - iLovePoint, byMarried, pMarriage->pid1, pMarriage->pid2); - - auto pmsg = CDBManager::instance().DirectQuery(szQuery); - - SQLResult* res = pmsg->Get(); - if (res->uiAffectedRows == 0 || res->uiAffectedRows == (uint32_t)-1) + if (!UpdateMarriageRow(pMarriage->pid1, pMarriage->pid2, iLovePoint, byMarried)) { sys_err("cannot update marriage : PID:%u %u", dwPID1, dwPID2); return; @@ -184,13 +330,7 @@ namespace marriage Align(dwPID1, dwPID2); - char szQuery[512]; - snprintf(szQuery, sizeof(szQuery), "DELETE FROM marriage WHERE pid1 = %u AND pid2 = %u", dwPID1, dwPID2); - - auto pmsg = CDBManager::instance().DirectQuery(szQuery); - - SQLResult* res = pmsg->Get(); - if (res->uiAffectedRows == 0 || res->uiAffectedRows == (uint32_t)-1) + if (!RemoveMarriageRow(dwPID1, dwPID2)) { sys_err("cannot delete marriage : PID:%u %u", dwPID1, dwPID2); return; @@ -227,14 +367,7 @@ namespace marriage Align(dwPID1, dwPID2); - char szQuery[512]; - snprintf(szQuery, sizeof(szQuery), "UPDATE marriage SET is_married = 1 WHERE pid1 = %u AND pid2 = %u", - pMarriage->pid1, pMarriage->pid2); - - auto pmsg = CDBManager::instance().DirectQuery(szQuery); - - SQLResult* res = pmsg->Get(); - if (res->uiAffectedRows == 0 || res->uiAffectedRows == (uint32_t)-1) + if (!MarkMarriageAsMarried(pMarriage->pid1, pMarriage->pid2)) { sys_err("cannot change engage to marriage : PID:%u %u", dwPID1, dwPID2); return;