db: prepare boot refine and shop queries

This commit is contained in:
server
2026-04-13 22:20:37 +02:00
parent 8a8aa54f02
commit f7f279fe90

View File

@@ -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 <size_t N>
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<int>(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<uint8_t>(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())
{