From f7f279fe90fa24917f2c0786a54fc2781bf7a094 Mon Sep 17 00:00:00 2001 From: server Date: Mon, 13 Apr 2026 22:20:37 +0200 Subject: [PATCH] db: prepare boot refine and shop queries --- src/db/ClientManagerBoot.cpp | 176 +++++++++++++++++++++++------------ 1 file changed, 115 insertions(+), 61 deletions(-) diff --git a/src/db/ClientManagerBoot.cpp b/src/db/ClientManagerBoot.cpp index 1419646..7c91a06 100644 --- a/src/db/ClientManagerBoot.cpp +++ b/src/db/ClientManagerBoot.cpp @@ -7,12 +7,39 @@ #include "CsvReader.h" #include "ProtoReader.h" +#include "libsql/Statement.h" using namespace std; extern int g_test_server; extern std::string g_stLocaleNameColumn; +namespace +{ + bool PrepareBootStmt(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()); + } + + template + void NullTerminateResult(char (&buffer)[N], unsigned long length) + { + size_t finalLength = length; + if (finalLength >= N) + finalLength = N - 1; + + buffer[finalLength] = '\0'; + } +} + bool CClientManager::InitializeTables() { if (!InitializeMobTable()) @@ -97,16 +124,38 @@ bool CClientManager::InitializeTables() bool CClientManager::InitializeRefineTable() { - char query[2048]; + CStmt stmt; + uint32_t id = 0; + int32_t cost = 0; + int32_t prob = 0; + uint32_t materialVnums[REFINE_MATERIAL_MAX_NUM] = {}; + int32_t materialCounts[REFINE_MATERIAL_MAX_NUM] = {}; + const std::string query = std::string("SELECT id, cost, prob, vnum0, count0, vnum1, count1, vnum2, count2, vnum3, count3, vnum4, count4 FROM refine_proto") + + GetTablePostfix(); - snprintf(query, sizeof(query), - "SELECT id, cost, prob, vnum0, count0, vnum1, count1, vnum2, count2, vnum3, count3, vnum4, count4 FROM refine_proto%s", - GetTablePostfix()); + if (!PrepareBootStmt(stmt, query)) + return false; - auto pkMsg = CDBManager::instance().DirectQuery(query); - SQLResult * pRes = pkMsg->Get(); + if (!stmt.BindResult(MYSQL_TYPE_LONG, &id) + || !stmt.BindResult(MYSQL_TYPE_LONG, &cost) + || !stmt.BindResult(MYSQL_TYPE_LONG, &prob)) + { + return false; + } - if (!pRes->uiNumRows) + for (int i = 0; i < REFINE_MATERIAL_MAX_NUM; ++i) + { + if (!stmt.BindResult(MYSQL_TYPE_LONG, &materialVnums[i]) + || !stmt.BindResult(MYSQL_TYPE_LONG, &materialCounts[i])) + { + return false; + } + } + + if (!stmt.Execute()) + return false; + + if (!stmt.iRows) return true; if (m_pRefineTable) @@ -116,30 +165,27 @@ bool CClientManager::InitializeRefineTable() m_pRefineTable = NULL; } - m_iRefineTableSize = pRes->uiNumRows; + m_iRefineTableSize = stmt.iRows; m_pRefineTable = new TRefineTable[m_iRefineTableSize]; memset(m_pRefineTable, 0, sizeof(TRefineTable) * m_iRefineTableSize); TRefineTable* prt = m_pRefineTable; - MYSQL_ROW data; - while ((data = mysql_fetch_row(pRes->pSQLResult))) + for (int row = 0; row < stmt.iRows; ++row) { - //const char* s_szQuery = "SELECT src_vnum, result_vnum, cost, prob, " - //"vnum0, count0, vnum1, count1, vnum2, count2, vnum3, count3, vnum4, count4 " + if (!stmt.Fetch()) + return false; - int col = 0; - //prt->src_vnum = atoi(data[col++]); - //prt->result_vnum = atoi(data[col++]); - str_to_number(prt->id, data[col++]); - str_to_number(prt->cost, data[col++]); - str_to_number(prt->prob, data[col++]); + prt->id = id; + prt->cost = cost; + prt->prob = prob; + prt->material_count = REFINE_MATERIAL_MAX_NUM; for (int i = 0; i < REFINE_MATERIAL_MAX_NUM; i++) { - str_to_number(prt->materials[i].vnum, data[col++]); - str_to_number(prt->materials[i].count, data[col++]); + prt->materials[i].vnum = materialVnums[i]; + prt->materials[i].count = materialCounts[i]; if (prt->materials[i].vnum == 0) { prt->material_count = i; @@ -429,25 +475,31 @@ bool CClientManager::InitializeMobTable() bool CClientManager::InitializeShopTable() { - MYSQL_ROW data; - int col; - - static const char * s_szQuery = + CStmt stmt; + uint32_t shopVnum = 0; + uint32_t npcVnum = 0; + uint32_t itemVnum = 0; + uint32_t itemCount = 0; + const char* query = "SELECT " "shop.vnum, " "shop.npc_vnum, " - "shop_item.item_vnum, " - "shop_item.count " + "COALESCE(shop_item.item_vnum, 0), " + "COALESCE(shop_item.count, 0) " "FROM shop LEFT JOIN shop_item " "ON shop.vnum = shop_item.shop_vnum ORDER BY shop.vnum, shop_item.item_vnum"; - auto pkMsg2 = CDBManager::instance().DirectQuery(s_szQuery); + if (!PrepareBootStmt(stmt, query) + || !stmt.BindResult(MYSQL_TYPE_LONG, &shopVnum) + || !stmt.BindResult(MYSQL_TYPE_LONG, &npcVnum) + || !stmt.BindResult(MYSQL_TYPE_LONG, &itemVnum) + || !stmt.BindResult(MYSQL_TYPE_LONG, &itemCount) + || !stmt.Execute()) + { + return false; + } - // shop의 vnum은 있는데 shop_item 이 없을경우... 실패로 처리되니 주의 요망. - // 고처야할부분 - SQLResult * pRes2 = pkMsg2->Get(); - - if (!pRes2->uiNumRows) + if (!stmt.iRows) { sys_err("InitializeShopTable : Table count is zero."); return false; @@ -463,12 +515,12 @@ bool CClientManager::InitializeShopTable() TShopTable * shop_table = m_pShopTable; - while ((data = mysql_fetch_row(pRes2->pSQLResult))) + for (int row = 0; row < stmt.iRows; ++row) { - col = 0; + if (!stmt.Fetch()) + return false; - int iShopVnum = 0; - str_to_number(iShopVnum, data[col++]); + int iShopVnum = static_cast(shopVnum); if (map_shop.end() == map_shop.find(iShopVnum)) { @@ -481,15 +533,15 @@ bool CClientManager::InitializeShopTable() else shop_table = map_shop[iShopVnum]; - str_to_number(shop_table->dwNPCVnum, data[col++]); + shop_table->dwNPCVnum = npcVnum; - if (!data[col]) // 아이템이 하나도 없으면 NULL이 리턴 되므로.. + if (!itemVnum) continue; TShopItemTable * pItem = &shop_table->items[shop_table->byItemCount]; - str_to_number(pItem->vnum, data[col++]); - str_to_number(pItem->count, data[col++]); + pItem->vnum = itemVnum; + pItem->count = static_cast(itemCount); ++shop_table->byItemCount; } @@ -515,40 +567,42 @@ bool CClientManager::InitializeQuestItemTable() { using namespace std; - static const char * s_szQuery = "SELECT vnum, name, %s FROM quest_item_proto ORDER BY vnum"; - char query[1024]; - snprintf(query, sizeof(query), s_szQuery, g_stLocaleNameColumn.c_str()); + snprintf(query, sizeof(query), "SELECT vnum, COALESCE(name, ''), COALESCE(%s, '') FROM quest_item_proto ORDER BY vnum", g_stLocaleNameColumn.c_str()); - auto pkMsg = CDBManager::instance().DirectQuery(query); - SQLResult * pRes = pkMsg->Get(); + CStmt stmt; + uint32_t vnum = 0; + char name[ITEM_NAME_MAX_LEN + 1] = {}; + char localeName[ITEM_NAME_MAX_LEN + 1] = {}; - if (!pRes->uiNumRows) + if (!PrepareBootStmt(stmt, query) + || !stmt.BindResult(MYSQL_TYPE_LONG, &vnum) + || !stmt.BindResult(MYSQL_TYPE_STRING, name, sizeof(name)) + || !stmt.BindResult(MYSQL_TYPE_STRING, localeName, sizeof(localeName)) + || !stmt.Execute()) + { + return false; + } + + if (!stmt.iRows) { sys_err("query error or no rows: %s", query); return false; } - MYSQL_ROW row; - - while ((row = mysql_fetch_row(pRes->pSQLResult))) + for (int row = 0; row < stmt.iRows; ++row) { - int col = 0; + if (!stmt.Fetch()) + return false; TItemTable tbl; memset(&tbl, 0, sizeof(tbl)); - str_to_number(tbl.dwVnum, row[col++]); - - if (row[col]) - strlcpy(tbl.szName, row[col], sizeof(tbl.szName)); - - col++; - - if (row[col]) - strlcpy(tbl.szLocaleName, row[col], sizeof(tbl.szLocaleName)); - - col++; + NullTerminateResult(name, stmt.GetResultLength(1)); + NullTerminateResult(localeName, stmt.GetResultLength(2)); + tbl.dwVnum = vnum; + strlcpy(tbl.szName, name, sizeof(tbl.szName)); + strlcpy(tbl.szLocaleName, localeName, sizeof(tbl.szLocaleName)); if (m_map_itemTableByVnum.find(tbl.dwVnum) != m_map_itemTableByVnum.end()) {