db: prepare player create and delete queries
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include "ItemAwardManager.h"
|
||||
#include "HB.h"
|
||||
#include "Cache.h"
|
||||
#include "libsql/Statement.h"
|
||||
|
||||
extern bool g_bHotBackup;
|
||||
|
||||
@@ -15,6 +16,22 @@ extern std::string g_stLocale;
|
||||
extern int g_test_server;
|
||||
extern int g_log;
|
||||
|
||||
namespace
|
||||
{
|
||||
bool PreparePlayerStmt(CStmt& stmt, const std::string& query, int slot = SQL_PLAYER)
|
||||
{
|
||||
CAsyncSQL* sql = CDBManager::instance().GetDirectSQL(slot);
|
||||
|
||||
if (!sql)
|
||||
{
|
||||
sys_err("player SQL handle is not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
return stmt.Prepare(sql, query.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// !!!!!!!!!!! IMPORTANT !!!!!!!!!!!!
|
||||
@@ -810,9 +827,7 @@ static time_by_id_map_t s_createTimeByAccountID;
|
||||
*/
|
||||
void CClientManager::__QUERY_PLAYER_CREATE(CPeer *peer, DWORD dwHandle, TPlayerCreatePacket* packet)
|
||||
{
|
||||
char queryStr[QUERY_MAX_LEN];
|
||||
int queryLen;
|
||||
int player_id;
|
||||
uint32_t player_id = 0;
|
||||
|
||||
// 한 계정에 X초 내로 캐릭터 생성을 할 수 없다.
|
||||
time_by_id_map_t::iterator it = s_createTimeByAccountID.find(packet->account_id);
|
||||
@@ -828,81 +843,53 @@ void CClientManager::__QUERY_PLAYER_CREATE(CPeer *peer, DWORD dwHandle, TPlayerC
|
||||
}
|
||||
}
|
||||
|
||||
queryLen = snprintf(queryStr, sizeof(queryStr),
|
||||
"SELECT pid%u FROM player_index%s WHERE id=%d", packet->account_index + 1, GetTablePostfix(), packet->account_id);
|
||||
uint32_t existingPid = 0;
|
||||
CStmt playerIndexStmt;
|
||||
const std::string playerIndexQuery = "SELECT pid" + std::to_string(packet->account_index + 1)
|
||||
+ " FROM player_index" + std::string(GetTablePostfix()) + " WHERE id=?";
|
||||
|
||||
auto pMsg0 = CDBManager::instance().DirectQuery(queryStr);
|
||||
|
||||
if (pMsg0->Get()->uiNumRows != 0)
|
||||
{
|
||||
if (!pMsg0->Get()->pSQLResult)
|
||||
{
|
||||
peer->EncodeHeader(DG::PLAYER_CREATE_FAILED, dwHandle, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
MYSQL_ROW row = mysql_fetch_row(pMsg0->Get()->pSQLResult);
|
||||
|
||||
DWORD dwPID = 0; str_to_number(dwPID, row[0]);
|
||||
if (row[0] && dwPID > 0)
|
||||
{
|
||||
peer->EncodeHeader(DG::PLAYER_CREATE_ALREADY, dwHandle, 0);
|
||||
sys_log(0, "ALREADY EXIST AccountChrIdx %d ID %d", packet->account_index, dwPID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!PreparePlayerStmt(playerIndexStmt, playerIndexQuery)
|
||||
|| !playerIndexStmt.BindParam(MYSQL_TYPE_LONG, &packet->account_id)
|
||||
|| !playerIndexStmt.BindResult(MYSQL_TYPE_LONG, &existingPid)
|
||||
|| !playerIndexStmt.Execute()
|
||||
|| playerIndexStmt.iRows == 0
|
||||
|| !playerIndexStmt.Fetch())
|
||||
{
|
||||
peer->EncodeHeader(DG::PLAYER_CREATE_FAILED, dwHandle, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (existingPid > 0)
|
||||
{
|
||||
peer->EncodeHeader(DG::PLAYER_CREATE_ALREADY, dwHandle, 0);
|
||||
sys_log(0, "ALREADY EXIST AccountChrIdx %d ID %d", packet->account_index, existingPid);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long long nameCount = 0;
|
||||
CStmt playerNameStmt;
|
||||
std::string playerNameQuery = "SELECT COUNT(*) FROM player" + std::string(GetTablePostfix()) + " WHERE name=?";
|
||||
|
||||
if (g_stLocale == "sjis")
|
||||
snprintf(queryStr, sizeof(queryStr),
|
||||
"SELECT COUNT(*) as count FROM player%s WHERE name='%s' collate sjis_japanese_ci",
|
||||
GetTablePostfix(), packet->player_table.name);
|
||||
else
|
||||
snprintf(queryStr, sizeof(queryStr),
|
||||
"SELECT COUNT(*) as count FROM player%s WHERE name='%s'", GetTablePostfix(), packet->player_table.name);
|
||||
playerNameQuery += " collate sjis_japanese_ci";
|
||||
|
||||
auto pMsg1 = CDBManager::instance().DirectQuery(queryStr);
|
||||
|
||||
if (pMsg1->Get()->uiNumRows)
|
||||
{
|
||||
if (!pMsg1->Get()->pSQLResult)
|
||||
{
|
||||
peer->EncodeHeader(DG::PLAYER_CREATE_FAILED, dwHandle, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
MYSQL_ROW row = mysql_fetch_row(pMsg1->Get()->pSQLResult);
|
||||
|
||||
if (*row[0] != '0')
|
||||
{
|
||||
sys_log(0, "ALREADY EXIST name %s, row[0] %s query %s", packet->player_table.name, row[0], queryStr);
|
||||
peer->EncodeHeader(DG::PLAYER_CREATE_ALREADY, dwHandle, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!PreparePlayerStmt(playerNameStmt, playerNameQuery)
|
||||
|| !playerNameStmt.BindParam(MYSQL_TYPE_STRING, packet->player_table.name, sizeof(packet->player_table.name))
|
||||
|| !playerNameStmt.BindResult(MYSQL_TYPE_LONGLONG, &nameCount)
|
||||
|| !playerNameStmt.Execute()
|
||||
|| playerNameStmt.iRows == 0
|
||||
|| !playerNameStmt.Fetch())
|
||||
{
|
||||
peer->EncodeHeader(DG::PLAYER_CREATE_FAILED, dwHandle, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
queryLen = snprintf(queryStr, sizeof(queryStr),
|
||||
"INSERT INTO player%s "
|
||||
"(id, account_id, name, level, st, ht, dx, iq, "
|
||||
"job, voice, dir, x, y, z, "
|
||||
"hp, mp, random_hp, random_sp, stat_point, stamina, part_base, part_main, part_hair, gold, playtime, "
|
||||
"skill_level, quickslot) "
|
||||
"VALUES(0, %u, '%s', %d, %d, %d, %d, %d, "
|
||||
"%d, %d, %d, %d, %d, %d, %d, "
|
||||
"%d, %d, %d, %d, %d, %d, %d, 0, %d, 0, ",
|
||||
GetTablePostfix(),
|
||||
packet->account_id, packet->player_table.name, packet->player_table.level, packet->player_table.st, packet->player_table.ht, packet->player_table.dx, packet->player_table.iq,
|
||||
packet->player_table.job, packet->player_table.voice, packet->player_table.dir, packet->player_table.x, packet->player_table.y, packet->player_table.z,
|
||||
packet->player_table.hp, packet->player_table.sp, packet->player_table.sRandomHP, packet->player_table.sRandomSP, packet->player_table.stat_point, packet->player_table.stamina, packet->player_table.part_base, packet->player_table.part_base, packet->player_table.gold);
|
||||
if (nameCount > 0)
|
||||
{
|
||||
sys_log(0, "ALREADY EXIST name %s", packet->player_table.name);
|
||||
peer->EncodeHeader(DG::PLAYER_CREATE_ALREADY, dwHandle, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
sys_log(0, "PlayerCreate accountid %d name %s level %d gold %d, st %d ht %d job %d",
|
||||
packet->account_id,
|
||||
@@ -913,39 +900,77 @@ void CClientManager::__QUERY_PLAYER_CREATE(CPeer *peer, DWORD dwHandle, TPlayerC
|
||||
packet->player_table.ht,
|
||||
packet->player_table.job);
|
||||
|
||||
static char text[8192 + 1];
|
||||
CStmt createPlayerStmt;
|
||||
uint16_t partHair = 0;
|
||||
int32_t playtime = 0;
|
||||
const std::string createPlayerQuery = "INSERT INTO player" + std::string(GetTablePostfix()) +
|
||||
" (id, account_id, name, level, st, ht, dx, iq, "
|
||||
"job, voice, dir, x, y, z, "
|
||||
"hp, mp, random_hp, random_sp, stat_point, stamina, part_base, part_main, part_hair, gold, playtime, "
|
||||
"skill_level, quickslot) "
|
||||
"VALUES(0, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
CDBManager::instance().EscapeString(text, packet->player_table.skills, sizeof(packet->player_table.skills));
|
||||
queryLen += snprintf(queryStr + queryLen, sizeof(queryStr) - queryLen, "'%s', ", text);
|
||||
if (g_test_server)
|
||||
sys_log(0, "Create_Player queryLen[%d] TEXT[%s]", queryLen, text);
|
||||
|
||||
CDBManager::instance().EscapeString(text, packet->player_table.quickslot, sizeof(packet->player_table.quickslot));
|
||||
queryLen += snprintf(queryStr + queryLen, sizeof(queryStr) - queryLen, "'%s')", text);
|
||||
|
||||
auto pMsg2 = CDBManager::instance().DirectQuery(queryStr);
|
||||
if (g_test_server)
|
||||
sys_log(0, "Create_Player queryLen[%d] TEXT[%s]", queryLen, text);
|
||||
|
||||
if (pMsg2->Get()->uiAffectedRows <= 0)
|
||||
if (!PreparePlayerStmt(createPlayerStmt, createPlayerQuery)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_LONG, &packet->account_id)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_STRING, packet->player_table.name, sizeof(packet->player_table.name))
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_TINY, &packet->player_table.level)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_SHORT, &packet->player_table.st)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_SHORT, &packet->player_table.ht)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_SHORT, &packet->player_table.dx)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_SHORT, &packet->player_table.iq)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_SHORT, &packet->player_table.job)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_TINY, &packet->player_table.voice)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_TINY, &packet->player_table.dir)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_LONG, &packet->player_table.x)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_LONG, &packet->player_table.y)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_LONG, &packet->player_table.z)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_LONG, &packet->player_table.hp)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_LONG, &packet->player_table.sp)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_LONG, &packet->player_table.sRandomHP)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_LONG, &packet->player_table.sRandomSP)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_SHORT, &packet->player_table.stat_point)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_SHORT, &packet->player_table.stamina)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_TINY, &packet->player_table.part_base)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_TINY, &packet->player_table.part_base)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_SHORT, &partHair)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_LONG, &packet->player_table.gold)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_LONG, &playtime)
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_BLOB, packet->player_table.skills, sizeof(packet->player_table.skills))
|
||||
|| !createPlayerStmt.BindParam(MYSQL_TYPE_BLOB, packet->player_table.quickslot, sizeof(packet->player_table.quickslot)))
|
||||
{
|
||||
peer->EncodeHeader(DG::PLAYER_CREATE_ALREADY, dwHandle, 0);
|
||||
sys_log(0, "ALREADY EXIST3 query: %s AffectedRows %lu", queryStr, pMsg2->Get()->uiAffectedRows);
|
||||
peer->EncodeHeader(DG::PLAYER_CREATE_FAILED, dwHandle, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
player_id = pMsg2->Get()->uiInsertID;
|
||||
|
||||
snprintf(queryStr, sizeof(queryStr), "UPDATE player_index%s SET pid%d=%d WHERE id=%d",
|
||||
GetTablePostfix(), packet->account_index + 1, player_id, packet->account_id);
|
||||
auto pMsg3 = CDBManager::instance().DirectQuery(queryStr);
|
||||
|
||||
if (pMsg3->Get()->uiAffectedRows <= 0)
|
||||
if (!createPlayerStmt.Execute() || createPlayerStmt.GetAffectedRows() <= 0)
|
||||
{
|
||||
sys_err("QUERY_ERROR: %s", queryStr);
|
||||
peer->EncodeHeader(DG::PLAYER_CREATE_ALREADY, dwHandle, 0);
|
||||
sys_log(0, "ALREADY EXIST3 name %s affected_rows %llu", packet->player_table.name, createPlayerStmt.GetAffectedRows());
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(queryStr, sizeof(queryStr), "DELETE FROM player%s WHERE id=%d", GetTablePostfix(), player_id);
|
||||
CDBManager::instance().DirectQuery(queryStr);
|
||||
player_id = static_cast<uint32_t>(createPlayerStmt.GetInsertId());
|
||||
|
||||
CStmt updatePlayerIndexStmt;
|
||||
const std::string updatePlayerIndexQuery = "UPDATE player_index" + std::string(GetTablePostfix())
|
||||
+ " SET pid" + std::to_string(packet->account_index + 1) + "=? WHERE id=?";
|
||||
|
||||
if (!PreparePlayerStmt(updatePlayerIndexStmt, updatePlayerIndexQuery)
|
||||
|| !updatePlayerIndexStmt.BindParam(MYSQL_TYPE_LONG, &player_id)
|
||||
|| !updatePlayerIndexStmt.BindParam(MYSQL_TYPE_LONG, &packet->account_id)
|
||||
|| !updatePlayerIndexStmt.Execute()
|
||||
|| updatePlayerIndexStmt.GetAffectedRows() <= 0)
|
||||
{
|
||||
sys_err("QUERY_ERROR: failed to update player_index for account %u pid %u", packet->account_id, player_id);
|
||||
|
||||
CStmt rollbackDeleteStmt;
|
||||
const std::string rollbackDeleteQuery = "DELETE FROM player" + std::string(GetTablePostfix()) + " WHERE id=?";
|
||||
|
||||
if (PreparePlayerStmt(rollbackDeleteStmt, rollbackDeleteQuery))
|
||||
{
|
||||
rollbackDeleteStmt.BindParam(MYSQL_TYPE_LONG, &player_id);
|
||||
rollbackDeleteStmt.Execute();
|
||||
}
|
||||
|
||||
peer->EncodeHeader(DG::PLAYER_CREATE_FAILED, dwHandle, 0);
|
||||
return;
|
||||
@@ -1082,12 +1107,15 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
|
||||
}
|
||||
|
||||
char queryStr[QUERY_MAX_LEN];
|
||||
CStmt archivePlayerStmt;
|
||||
const std::string archivePlayerQuery = "INSERT INTO player" + std::string(GetTablePostfix())
|
||||
+ "_deleted SELECT * FROM player" + std::string(GetTablePostfix()) + " WHERE id=?";
|
||||
|
||||
snprintf(queryStr, sizeof(queryStr), "INSERT INTO player%s_deleted SELECT * FROM player%s WHERE id=%d",
|
||||
GetTablePostfix(), GetTablePostfix(), pi->player_id);
|
||||
auto pIns = CDBManager::instance().DirectQuery(queryStr);
|
||||
|
||||
if (pIns->Get()->uiAffectedRows == 0 || pIns->Get()->uiAffectedRows == (uint32_t)-1)
|
||||
if (!PreparePlayerStmt(archivePlayerStmt, archivePlayerQuery)
|
||||
|| !archivePlayerStmt.BindParam(MYSQL_TYPE_LONG, &pi->player_id)
|
||||
|| !archivePlayerStmt.Execute()
|
||||
|| archivePlayerStmt.GetAffectedRows() == 0
|
||||
|| archivePlayerStmt.GetAffectedRows() == static_cast<unsigned long long>(-1))
|
||||
{
|
||||
sys_log(0, "PLAYER_DELETE FAILED %u CANNOT INSERT TO player%s_deleted", dwPID, GetTablePostfix());
|
||||
|
||||
@@ -1099,10 +1127,6 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
|
||||
// 삭제 성공
|
||||
sys_log(0, "PLAYER_DELETE SUCCESS %u", dwPID);
|
||||
|
||||
char account_index_string[16];
|
||||
|
||||
snprintf(account_index_string, sizeof(account_index_string), "player_id%d", m_iPlayerIDStart + pi->account_index);
|
||||
|
||||
// 플레이어 테이블을 캐쉬에서 삭제한다.
|
||||
CPlayerTableCache * pkPlayerCache = GetPlayerCache(pi->player_id);
|
||||
|
||||
@@ -1131,15 +1155,15 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
|
||||
m_map_pkItemCacheSetPtr.erase(pi->player_id);
|
||||
}
|
||||
|
||||
snprintf(queryStr, sizeof(queryStr), "UPDATE player_index%s SET pid%u=0 WHERE pid%u=%d",
|
||||
GetTablePostfix(),
|
||||
pi->account_index + 1,
|
||||
pi->account_index + 1,
|
||||
pi->player_id);
|
||||
CStmt resetPlayerIndexStmt;
|
||||
const std::string resetPlayerIndexQuery = "UPDATE player_index" + std::string(GetTablePostfix())
|
||||
+ " SET pid" + std::to_string(pi->account_index + 1) + "=0 WHERE pid" + std::to_string(pi->account_index + 1) + "=?";
|
||||
|
||||
auto pMsg = CDBManager::instance().DirectQuery(queryStr);
|
||||
|
||||
if (pMsg->Get()->uiAffectedRows == 0 || pMsg->Get()->uiAffectedRows == (uint32_t)-1)
|
||||
if (!PreparePlayerStmt(resetPlayerIndexStmt, resetPlayerIndexQuery)
|
||||
|| !resetPlayerIndexStmt.BindParam(MYSQL_TYPE_LONG, &pi->player_id)
|
||||
|| !resetPlayerIndexStmt.Execute()
|
||||
|| resetPlayerIndexStmt.GetAffectedRows() == 0
|
||||
|| resetPlayerIndexStmt.GetAffectedRows() == static_cast<unsigned long long>(-1))
|
||||
{
|
||||
sys_log(0, "PLAYER_DELETE FAIL WHEN UPDATE account table");
|
||||
peer->EncodeHeader(DG::PLAYER_DELETE_FAILED, pi->dwHandle, 1);
|
||||
@@ -1147,11 +1171,26 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(queryStr, sizeof(queryStr), "DELETE FROM player%s WHERE id=%d", GetTablePostfix(), pi->player_id);
|
||||
CDBManager::instance().DirectQuery(queryStr);
|
||||
CStmt deletePlayerStmt;
|
||||
const std::string deletePlayerQuery = "DELETE FROM player" + std::string(GetTablePostfix()) + " WHERE id=?";
|
||||
if (PreparePlayerStmt(deletePlayerStmt, deletePlayerQuery))
|
||||
{
|
||||
deletePlayerStmt.BindParam(MYSQL_TYPE_LONG, &pi->player_id);
|
||||
deletePlayerStmt.Execute();
|
||||
}
|
||||
|
||||
snprintf(queryStr, sizeof(queryStr), "DELETE FROM item%s WHERE owner_id=%d AND (window < %d or window = %d)", GetTablePostfix(), pi->player_id, SAFEBOX, DRAGON_SOUL_INVENTORY);
|
||||
CDBManager::instance().DirectQuery(queryStr);
|
||||
CStmt deleteItemStmt;
|
||||
int32_t safeboxWindow = SAFEBOX;
|
||||
int32_t dragonSoulInventory = DRAGON_SOUL_INVENTORY;
|
||||
const std::string deleteItemQuery = "DELETE FROM item" + std::string(GetTablePostfix())
|
||||
+ " WHERE owner_id=? AND (window < ? or window = ?)";
|
||||
if (PreparePlayerStmt(deleteItemStmt, deleteItemQuery))
|
||||
{
|
||||
deleteItemStmt.BindParam(MYSQL_TYPE_LONG, &pi->player_id);
|
||||
deleteItemStmt.BindParam(MYSQL_TYPE_LONG, &safeboxWindow);
|
||||
deleteItemStmt.BindParam(MYSQL_TYPE_LONG, &dragonSoulInventory);
|
||||
deleteItemStmt.Execute();
|
||||
}
|
||||
|
||||
snprintf(queryStr, sizeof(queryStr), "DELETE FROM quest%s WHERE dwPID=%d", GetTablePostfix(), pi->player_id);
|
||||
CDBManager::instance().AsyncQuery(queryStr);
|
||||
@@ -1372,4 +1411,3 @@ void CClientManager::FlushPlayerCacheSet(DWORD pid)
|
||||
delete c;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user