aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2020-07-30 19:50:24 +0200
committerShauren <shauren.trinity@gmail.com>2020-07-30 19:50:24 +0200
commite94350fcc31cedb5a8140a71e2b2a03ab4125927 (patch)
treeb69c11790629ae1efb4ff9b408ccad0260c36069 /src
parent2f0893d279ddab86ae7c3e4fd1d7a47b15e938f7 (diff)
Core/Mail: Refactor mail loading to execute 2 database queries instead of 1+mails.size()
Diffstat (limited to 'src')
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp4
-rw-r--r--src/server/game/Entities/Player/Player.cpp166
-rw-r--r--src/server/game/Entities/Player/Player.h2
-rw-r--r--src/server/game/Handlers/SocialHandler.cpp1
4 files changed, 86 insertions, 87 deletions
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index bb68b65d3c8..dd161ef98cc 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -122,7 +122,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, playedTime, 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, playedTime, 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, playedTime, 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);
@@ -428,7 +428,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);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index c6cca97fcc2..80ac886585d 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -4138,6 +4138,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();
@@ -4173,41 +4191,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();
-
- 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;
- }
+ for (Item* item : itemsItr->second)
+ draft.AddItem(item);
- 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);
@@ -18403,61 +18394,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);
+ CharacterDatabase.CommitTransaction(trans);
+ return nullptr;
+ }
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_MAIL_ITEM);
- stmt->setUInt32(0, itemGuid);
- CharacterDatabase.Execute(stmt);
+ Item* item = NewItemOrBag(proto);
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
- stmt->setUInt32(0, itemGuid);
- CharacterDatabase.Execute(stmt);
- continue;
- }
+ 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);
- Item* item = NewItemOrBag(proto);
+ CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM);
+ stmt->setUInt32(0, itemGuid);
+ CharacterDatabase.Execute(stmt);
- 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);
+ item->FSetState(ITEM_REMOVED);
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM);
- stmt->setUInt32(0, itemGuid);
- CharacterDatabase.Execute(stmt);
+ CharacterDatabaseTransaction temp = CharacterDatabaseTransaction(nullptr);
+ item->SaveToDB(temp); // it also deletes item object !
+ return nullptr;
+ }
- item->FSetState(ITEM_REMOVED);
+ if (mail)
+ mail->AddItem(itemGuid, itemEntry);
- CharacterDatabaseTransaction temp = CharacterDatabaseTransaction(nullptr);
- item->SaveToDB(temp); // it also deletes item object !
- continue;
- }
+ if (player)
+ player->AddMItem(item);
- AddMItem(item);
- }
- while (result->NextRow());
+ return item;
}
void Player::_LoadMailInit(PreparedQueryResult resultUnread, PreparedQueryResult resultDelivery)
@@ -18481,6 +18465,8 @@ void Player::_LoadMail()
stmt->setUInt32(0, GetGUID().GetCounter());
PreparedQueryResult result = CharacterDatabase.Query(stmt);
+ std::unordered_map<uint32, Mail*> mailById;
+
if (result)
{
do
@@ -18494,14 +18480,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].GetUInt32();
- m->COD = fields[10].GetUInt32();
- 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))
{
@@ -18511,13 +18496,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;
}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 85c2eb2c059..542cca2f29f 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -2229,7 +2229,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void _LoadInventory(PreparedQueryResult result, uint32 timeDiff);
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);
diff --git a/src/server/game/Handlers/SocialHandler.cpp b/src/server/game/Handlers/SocialHandler.cpp
index 4271570e945..7b183355ead 100644
--- a/src/server/game/Handlers/SocialHandler.cpp
+++ b/src/server/game/Handlers/SocialHandler.cpp
@@ -22,6 +22,7 @@
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Player.h"
+#include "QueryCallback.h"
#include "RBAC.h"
#include "Realm.h"
#include "SocialMgr.h"