Refactor mail loading to execute 2 database queries instead of 1+mails.size()

This commit is contained in:
Shauren
2020-08-01 15:15:07 +02:00
committed by Ovahlord
parent 1c1c62d108
commit adb7e4dba8
3 changed files with 92 additions and 95 deletions

View File

@@ -128,7 +128,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES, "SELECT instanceId, releaseTime FROM account_instance_times WHERE accountId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS_SPEC, "SELECT button, action, type FROM character_action WHERE guid = ? AND spec = ? ORDER BY button", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_MAILITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, creationTime, text, item_guid, itemEntry, owner_guid FROM mail_items mi JOIN item_instance ii ON mi.item_guid = ii.guid WHERE mail_id = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_MAILITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, creationTime, text, item_guid, itemEntry, ii.owner_guid, m.id FROM mail_items mi INNER JOIN mail m ON mi.mail_id = m.id LEFT JOIN item_instance ii ON mi.item_guid = ii.guid WHERE m.receiver = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_AUCTION_ITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, creationTime, text, itemguid, itemEntry FROM auctionhouse ah JOIN item_instance ii ON ah.itemguid = ii.guid", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_AUCTIONS, "SELECT id, houseid, itemguid, itemEntry, count, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit FROM auctionhouse ah INNER JOIN item_instance ii ON ii.guid = ah.itemguid", CONNECTION_SYNCH);
PrepareStatement(CHAR_INS_AUCTION, "INSERT INTO auctionhouse (id, houseid, itemguid, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
@@ -467,7 +467,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_CHAR_COD_ITEM_MAIL, "SELECT id, messageType, mailTemplateId, sender, subject, body, money, has_items FROM mail WHERE receiver = ? AND has_items <> 0 AND cod <> 0", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_SOCIAL, "SELECT DISTINCT guid FROM character_social WHERE friend = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_OLD_CHARS, "SELECT guid, deleteInfos_Account FROM characters WHERE deleteDate IS NOT NULL AND deleteDate < ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_MAIL, "SELECT id, messageType, sender, receiver, subject, body, has_items, expire_time, deliver_time, money, cod, checked, stationery, mailTemplateId FROM mail WHERE receiver = ? ORDER BY id DESC", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_MAIL, "SELECT id, messageType, sender, receiver, subject, body, expire_time, deliver_time, money, cod, checked, stationery, mailTemplateId FROM mail WHERE receiver = ? ORDER BY id DESC", CONNECTION_SYNCH);
PrepareStatement(CHAR_DEL_CHAR_AURA_FROZEN, "DELETE FROM character_aura WHERE spell = 9454 AND guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHAR_INVENTORY_COUNT_ITEM, "SELECT COUNT(itemEntry) FROM character_inventory ci INNER JOIN item_instance ii ON ii.guid = ci.item WHERE itemEntry = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_MAIL_COUNT_ITEM, "SELECT COUNT(itemEntry) FROM mail_items mi INNER JOIN item_instance ii ON ii.guid = mi.item_guid WHERE itemEntry = ?", CONNECTION_SYNCH);

View File

@@ -3833,6 +3833,24 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
if (resultMail)
{
std::unordered_map<uint32, std::vector<Item*>> itemsByMail;
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS);
stmt->setUInt32(0, guid);
PreparedQueryResult resultItems = CharacterDatabase.Query(stmt);
if (resultItems)
{
do
{
Field* fields = resultItems->Fetch();
uint32 mailId = fields[14].GetUInt32();
if (Item* mailItem = _LoadMailedItem(playerguid, nullptr, mailId, nullptr, fields))
itemsByMail[mailId].push_back(mailItem);
} while (resultItems->NextRow());
}
do
{
Field* mailFields = resultMail->Fetch();
@@ -3868,41 +3886,14 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
if (mailTemplateId)
draft = MailDraft(mailTemplateId, false); // items are already included
if (has_items)
auto itemsItr = itemsByMail.find(mail_id);
if (itemsItr != itemsByMail.end())
{
// Data needs to be at first place for Item::LoadFromDB
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS);
stmt->setUInt32(0, mail_id);
PreparedQueryResult resultItems = CharacterDatabase.Query(stmt);
if (resultItems)
{
do
{
Field* itemFields = resultItems->Fetch();
ObjectGuid::LowType item_guidlow = itemFields[11].GetUInt32();
uint32 item_template = itemFields[12].GetUInt32();
for (Item* item : itemsItr->second)
draft.AddItem(item);
ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(item_template);
if (!itemProto)
{
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
stmt->setUInt32(0, item_guidlow);
trans->Append(stmt);
continue;
}
Item* pItem = NewItemOrBag(itemProto);
if (!pItem->LoadFromDB(item_guidlow, playerguid, itemFields, item_template))
{
pItem->FSetState(ITEM_REMOVED);
pItem->SaveToDB(trans); // it also deletes item object!
continue;
}
draft.AddItem(pItem);
}
while (resultItems->NextRow());
}
// MailDraft will take care of freeing memory
itemsByMail.erase(itemsItr);
}
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID);
@@ -18324,61 +18315,54 @@ Item* Player::_LoadItem(CharacterDatabaseTransaction& trans, uint32 zoneId, uint
}
// load mailed item which should receive current player
void Player::_LoadMailedItems(Mail* mail)
Item* Player::_LoadMailedItem(ObjectGuid const& playerGuid, Player* player, uint32 mailId, Mail* mail, Field* fields)
{
// data needs to be at first place for Item::LoadFromDB
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS);
stmt->setUInt32(0, mail->messageID);
PreparedQueryResult result = CharacterDatabase.Query(stmt);
if (!result)
return;
ObjectGuid::LowType itemGuid = fields[11].GetUInt32();
uint32 itemEntry = fields[12].GetUInt32();
do
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemEntry);
if (!proto)
{
Field* fields = result->Fetch();
TC_LOG_ERROR("entities.player", "Player '%s' (%s) has unknown item in mailed items (GUID: %u, Entry: %u) in mail (%u), deleted.",
player ? player->GetName().c_str() : "<unknown>", playerGuid.ToString().c_str(), itemGuid, itemEntry, mailId);
ObjectGuid::LowType itemGuid = fields[11].GetUInt32();
uint32 itemTemplate = fields[12].GetUInt32();
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
mail->AddItem(itemGuid, itemTemplate);
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_MAIL_ITEM);
stmt->setUInt32(0, itemGuid);
trans->Append(stmt);
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemTemplate);
Item::DeleteFromDB(trans, itemGuid);
if (!proto)
{
TC_LOG_ERROR("entities.player", "Player '%s' (%s) has unknown item_template in mailed items (GUID: %u, Entry: %u) in mail (%u), deleted.",
GetName().c_str(), GetGUID().ToString().c_str(), itemGuid, itemTemplate, mail->messageID);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_MAIL_ITEM);
stmt->setUInt32(0, itemGuid);
CharacterDatabase.Execute(stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
stmt->setUInt32(0, itemGuid);
CharacterDatabase.Execute(stmt);
continue;
}
Item* item = NewItemOrBag(proto);
if (!item->LoadFromDB(itemGuid, ObjectGuid(HighGuid::Player, fields[13].GetUInt32()), fields, itemTemplate))
{
TC_LOG_ERROR("entities.player", "Player::_LoadMailedItems: Item (GUID: %u) in mail (%u) doesn't exist, deleted from mail.", itemGuid, mail->messageID);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM);
stmt->setUInt32(0, itemGuid);
CharacterDatabase.Execute(stmt);
item->FSetState(ITEM_REMOVED);
CharacterDatabaseTransaction temp = CharacterDatabaseTransaction(nullptr);
item->SaveToDB(temp); // it also deletes item object !
continue;
}
AddMItem(item);
CharacterDatabase.CommitTransaction(trans);
return nullptr;
}
while (result->NextRow());
Item* item = NewItemOrBag(proto);
ObjectGuid ownerGuid = fields[13].GetUInt32() ? ObjectGuid::Create<HighGuid::Player>(fields[13].GetUInt32()) : ObjectGuid::Empty;
if (!item->LoadFromDB(itemGuid, ownerGuid, fields, itemEntry))
{
TC_LOG_ERROR("entities.player", "Player::_LoadMailedItems: Item (GUID: %u) in mail (%u) doesn't exist, deleted from mail.", itemGuid, mailId);
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM);
stmt->setUInt32(0, itemGuid);
CharacterDatabase.Execute(stmt);
item->FSetState(ITEM_REMOVED);
CharacterDatabaseTransaction temp = CharacterDatabaseTransaction(nullptr);
item->SaveToDB(temp); // it also deletes item object !
return nullptr;
}
if (mail)
mail->AddItem(itemGuid, itemEntry);
if (player)
player->AddMItem(item);
return item;
}
void Player::_LoadMailInit(PreparedQueryResult resultUnread, PreparedQueryResult resultDelivery)
@@ -18402,6 +18386,8 @@ void Player::_LoadMail()
stmt->setUInt32(0, GetGUID().GetCounter());
PreparedQueryResult result = CharacterDatabase.Query(stmt);
std::unordered_map<uint32, Mail*> mailById;
if (result)
{
do
@@ -18415,14 +18401,13 @@ void Player::_LoadMail()
m->receiver = fields[3].GetUInt32();
m->subject = fields[4].GetString();
m->body = fields[5].GetString();
bool has_items = fields[6].GetBool();
m->expire_time = time_t(fields[7].GetUInt32());
m->deliver_time = time_t(fields[8].GetUInt32());
m->money = fields[9].GetUInt64();
m->COD = fields[10].GetUInt64();
m->checked = fields[11].GetUInt8();
m->stationery = fields[12].GetUInt8();
m->mailTemplateId = fields[13].GetInt16();
m->expire_time = time_t(fields[6].GetUInt32());
m->deliver_time = time_t(fields[7].GetUInt32());
m->money = fields[8].GetUInt32();
m->COD = fields[9].GetUInt32();
m->checked = fields[10].GetUInt8();
m->stationery = fields[11].GetUInt8();
m->mailTemplateId = fields[12].GetInt16();
if (m->mailTemplateId && !sMailTemplateStore.LookupEntry(m->mailTemplateId))
{
@@ -18431,14 +18416,26 @@ void Player::_LoadMail()
}
m->state = MAIL_STATE_UNCHANGED;
if (has_items)
_LoadMailedItems(m);
m_mail.push_back(m);
mailById[m->messageID] = m;
}
while (result->NextRow());
}
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS);
stmt->setUInt32(0, GetGUID().GetCounter());
result = CharacterDatabase.Query(stmt);
if (result)
{
do
{
Field* fields = result->Fetch();
uint32 mailId = fields[14].GetUInt32();
_LoadMailedItem(GetGUID(), this, mailId, mailById[mailId], fields);
} while (result->NextRow());
}
m_mailsLoaded = true;
}

View File

@@ -2467,7 +2467,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void _LoadVoidStorage(PreparedQueryResult result);
void _LoadMailInit(PreparedQueryResult resultUnread, PreparedQueryResult resultDelivery);
void _LoadMail();
void _LoadMailedItems(Mail* mail);
static Item* _LoadMailedItem(ObjectGuid const& playerGuid, Player* player, uint32 mailId, Mail* mail, Field* fields);
void _LoadQuestStatus(PreparedQueryResult result);
void _LoadQuestStatusRewarded(PreparedQueryResult result);
void _LoadDailyQuestStatus(PreparedQueryResult result);