DB Layer:
- Make SQL Transactions actual objects used in code. (Thanks to Derex for the idea) * Uncommitted transactions will be automatically rolled back and cleaned up using ACE_Refcounted_Auto_Ptr, so no need to call Rollback() in the code. * Prevents recursive transactions and makes developers aware of transactions going on. * Gets rid of unneccesary overhead iterating over a concurrent map. - Some cleanups in affected code, including better usage of transaction control in AH / mail related code to prevent data loss. *** Experimental, use at own risk, recommended to backup your DBs. *** --HG-- branch : trunk
This commit is contained in:
@@ -88,7 +88,7 @@ uint32 AuctionHouseMgr::GetAuctionDeposit(AuctionHouseEntry const* entry, uint32
|
||||
}
|
||||
|
||||
//does not clear ram
|
||||
void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry *auction)
|
||||
void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry *auction, SQLTransaction& trans)
|
||||
{
|
||||
Item *pItem = GetAItem(auction->item_guidlow);
|
||||
if (!pItem)
|
||||
@@ -146,7 +146,7 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry *auction)
|
||||
|
||||
// set owner to bidder (to prevent delete item with sender char deleting)
|
||||
// owner in `data` will set at mail receive and item extracting
|
||||
CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'",auction->bidder,pItem->GetGUIDLow());
|
||||
trans->PAppend("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'",auction->bidder,pItem->GetGUIDLow());
|
||||
|
||||
if (bidder)
|
||||
{
|
||||
@@ -157,11 +157,11 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry *auction)
|
||||
|
||||
MailDraft(msgAuctionWonSubject.str(), msgAuctionWonBody.str())
|
||||
.AddItem(pItem)
|
||||
.SendMailTo(MailReceiver(bidder,auction->bidder), auction, MAIL_CHECK_MASK_COPIED);
|
||||
.SendMailTo(trans, MailReceiver(bidder,auction->bidder), auction, MAIL_CHECK_MASK_COPIED);
|
||||
}
|
||||
}
|
||||
|
||||
void AuctionHouseMgr::SendAuctionSalePendingMail(AuctionEntry * auction)
|
||||
void AuctionHouseMgr::SendAuctionSalePendingMail(AuctionEntry * auction, SQLTransaction& trans)
|
||||
{
|
||||
uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER);
|
||||
Player *owner = sObjectMgr.GetPlayer(owner_guid);
|
||||
@@ -186,12 +186,12 @@ void AuctionHouseMgr::SendAuctionSalePendingMail(AuctionEntry * auction)
|
||||
sLog.outDebug("AuctionSalePending body string : %s", msgAuctionSalePendingBody.str().c_str());
|
||||
|
||||
MailDraft(msgAuctionSalePendingSubject.str(), msgAuctionSalePendingBody.str())
|
||||
.SendMailTo(MailReceiver(owner,auction->owner), auction, MAIL_CHECK_MASK_COPIED);
|
||||
.SendMailTo(trans, MailReceiver(owner,auction->owner), auction, MAIL_CHECK_MASK_COPIED);
|
||||
}
|
||||
}
|
||||
|
||||
//call this method to send mail to auction owner, when auction is successful, it does not clear ram
|
||||
void AuctionHouseMgr::SendAuctionSuccessfulMail(AuctionEntry * auction)
|
||||
void AuctionHouseMgr::SendAuctionSuccessfulMail(AuctionEntry * auction, SQLTransaction& trans)
|
||||
{
|
||||
uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER);
|
||||
Player *owner = sObjectMgr.GetPlayer(owner_guid);
|
||||
@@ -224,12 +224,12 @@ void AuctionHouseMgr::SendAuctionSuccessfulMail(AuctionEntry * auction)
|
||||
}
|
||||
MailDraft(msgAuctionSuccessfulSubject.str(), auctionSuccessfulBody.str())
|
||||
.AddMoney(profit)
|
||||
.SendMailTo(MailReceiver(owner,auction->owner), auction, MAIL_CHECK_MASK_COPIED, sWorld.getConfig(CONFIG_MAIL_DELIVERY_DELAY));
|
||||
.SendMailTo(trans, MailReceiver(owner,auction->owner), auction, MAIL_CHECK_MASK_COPIED, sWorld.getConfig(CONFIG_MAIL_DELIVERY_DELAY));
|
||||
}
|
||||
}
|
||||
|
||||
//does not clear ram
|
||||
void AuctionHouseMgr::SendAuctionExpiredMail(AuctionEntry * auction)
|
||||
void AuctionHouseMgr::SendAuctionExpiredMail(AuctionEntry * auction, SQLTransaction& trans)
|
||||
{
|
||||
//return an item in auction to its owner by mail
|
||||
Item *pItem = GetAItem(auction->item_guidlow);
|
||||
@@ -250,10 +250,58 @@ void AuctionHouseMgr::SendAuctionExpiredMail(AuctionEntry * auction)
|
||||
|
||||
MailDraft(subject.str(), "") // TODO: fix body
|
||||
.AddItem(pItem)
|
||||
.SendMailTo(MailReceiver(owner,auction->owner), auction, MAIL_CHECK_MASK_COPIED);
|
||||
.SendMailTo(trans, MailReceiver(owner,auction->owner), auction, MAIL_CHECK_MASK_COPIED, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//this function sends mail to old bidder
|
||||
void AuctionHouseMgr::SendAuctionOutbiddedMail(AuctionEntry *auction, uint32 newPrice, Player* newBidder, SQLTransaction& trans)
|
||||
{
|
||||
uint64 oldBidder_guid = MAKE_NEW_GUID(auction->bidder,0, HIGHGUID_PLAYER);
|
||||
Player *oldBidder = sObjectMgr.GetPlayer(oldBidder_guid);
|
||||
|
||||
uint32 oldBidder_accId = 0;
|
||||
if (!oldBidder)
|
||||
oldBidder_accId = sObjectMgr.GetPlayerAccountIdByGUID(oldBidder_guid);
|
||||
|
||||
// old bidder exist
|
||||
if (oldBidder || oldBidder_accId)
|
||||
{
|
||||
std::ostringstream msgAuctionOutbiddedSubject;
|
||||
msgAuctionOutbiddedSubject << auction->item_template << ":0:" << AUCTION_OUTBIDDED << ":0:0";
|
||||
|
||||
if (oldBidder && newBidder)
|
||||
oldBidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, newBidder->GetGUID(), newPrice, auction->GetAuctionOutBid(), auction->item_template);
|
||||
|
||||
MailDraft(msgAuctionOutbiddedSubject.str(), "") // TODO: fix body
|
||||
.AddMoney(auction->bid)
|
||||
.SendMailTo(trans, MailReceiver(oldBidder, auction->bidder), auction, MAIL_CHECK_MASK_COPIED);
|
||||
}
|
||||
}
|
||||
|
||||
//this function sends mail, when auction is cancelled to old bidder
|
||||
void AuctionHouseMgr::SendAuctionCancelledToBidderMail(AuctionEntry* auction, SQLTransaction& trans)
|
||||
{
|
||||
uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER);
|
||||
Player *bidder = sObjectMgr.GetPlayer(bidder_guid);
|
||||
|
||||
uint32 bidder_accId = 0;
|
||||
if (!bidder)
|
||||
bidder_accId = sObjectMgr.GetPlayerAccountIdByGUID(bidder_guid);
|
||||
|
||||
// bidder exist
|
||||
if (bidder || bidder_accId)
|
||||
{
|
||||
std::ostringstream msgAuctionCancelledSubject;
|
||||
msgAuctionCancelledSubject << auction->item_template << ":0:" << AUCTION_CANCELLED_TO_BIDDER << ":0:0";
|
||||
|
||||
MailDraft(msgAuctionCancelledSubject.str(), "") // TODO: fix body
|
||||
.AddMoney(auction->bid)
|
||||
.SendMailTo(trans, MailReceiver(bidder, auction->bidder), auction, MAIL_CHECK_MASK_COPIED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AuctionHouseMgr::LoadAuctionItems()
|
||||
{
|
||||
// data needs to be at first place for Item::LoadFromDB
|
||||
@@ -342,6 +390,10 @@ void AuctionHouseMgr::LoadAuctions()
|
||||
|
||||
barGoLink bar(AuctionCount);
|
||||
|
||||
//- TODO: Get rid of horrible design so we don't have to use transaction here to statisfy
|
||||
//- function parameters.
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
|
||||
AuctionEntry *aItem;
|
||||
|
||||
do
|
||||
@@ -366,7 +418,7 @@ void AuctionHouseMgr::LoadAuctions()
|
||||
CreatureData const* auctioneerData = sObjectMgr.GetCreatureData(aItem->auctioneer);
|
||||
if (!auctioneerData)
|
||||
{
|
||||
aItem->DeleteFromDB();
|
||||
aItem->DeleteFromDB(trans);
|
||||
sLog.outError("Auction %u has not a existing auctioneer (GUID : %u)", aItem->Id, aItem->auctioneer);
|
||||
delete aItem;
|
||||
continue;
|
||||
@@ -375,7 +427,7 @@ void AuctionHouseMgr::LoadAuctions()
|
||||
CreatureInfo const* auctioneerInfo = sObjectMgr.GetCreatureTemplate(auctioneerData->id);
|
||||
if (!auctioneerInfo)
|
||||
{
|
||||
aItem->DeleteFromDB();
|
||||
aItem->DeleteFromDB(trans);
|
||||
sLog.outError("Auction %u has not a existing auctioneer (GUID : %u Entry: %u)", aItem->Id, aItem->auctioneer,auctioneerData->id);
|
||||
delete aItem;
|
||||
continue;
|
||||
@@ -384,7 +436,7 @@ void AuctionHouseMgr::LoadAuctions()
|
||||
aItem->auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(auctioneerInfo->faction_A);
|
||||
if (!aItem->auctionHouseEntry)
|
||||
{
|
||||
aItem->DeleteFromDB();
|
||||
aItem->DeleteFromDB(trans);
|
||||
sLog.outError("Auction %u has auctioneer (GUID : %u Entry: %u) with wrong faction %u",
|
||||
aItem->Id, aItem->auctioneer,auctioneerData->id,auctioneerInfo->faction_A);
|
||||
delete aItem;
|
||||
@@ -395,7 +447,7 @@ void AuctionHouseMgr::LoadAuctions()
|
||||
// and item_template in fact (GetAItem will fail if problematic in result check in AuctionHouseMgr::LoadAuctionItems)
|
||||
if (!GetAItem(aItem->item_guidlow))
|
||||
{
|
||||
aItem->DeleteFromDB();
|
||||
aItem->DeleteFromDB(trans);
|
||||
sLog.outError("Auction %u has not a existing item : %u", aItem->Id, aItem->item_guidlow);
|
||||
delete aItem;
|
||||
continue;
|
||||
@@ -405,6 +457,8 @@ void AuctionHouseMgr::LoadAuctions()
|
||||
|
||||
} while (result->NextRow());
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString(">> Loaded %u auctions", AuctionCount);
|
||||
}
|
||||
@@ -506,35 +560,20 @@ void AuctionHouseObject::Update()
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
if (result->GetRowCount() == 0)
|
||||
return;
|
||||
|
||||
vector<uint32> expiredAuctions;
|
||||
|
||||
do
|
||||
{
|
||||
uint32 tmpdata = result->Fetch()->GetUInt32();
|
||||
expiredAuctions.push_back(tmpdata);
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
while (!expiredAuctions.empty())
|
||||
{
|
||||
vector<uint32>::iterator iter = expiredAuctions.begin();
|
||||
|
||||
// from auctionhousehandler.cpp, creates auction pointer & player pointer
|
||||
AuctionEntry* auction = GetAuction(*iter);
|
||||
|
||||
// Erase the auction from the vector.
|
||||
expiredAuctions.erase(iter);
|
||||
AuctionEntry* auction = GetAuction(result->Fetch()->GetUInt32());
|
||||
|
||||
if (!auction)
|
||||
continue;
|
||||
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
|
||||
///- Either cancel the auction if there was no bidder
|
||||
if (auction->bidder == 0)
|
||||
{
|
||||
sAuctionMgr.SendAuctionExpiredMail(auction);
|
||||
sAuctionMgr.SendAuctionExpiredMail(auction, trans);
|
||||
sScriptMgr.OnAuctionExpire(this, auction);
|
||||
}
|
||||
///- Or perform the transaction
|
||||
@@ -543,19 +582,21 @@ void AuctionHouseObject::Update()
|
||||
//we should send an "item sold" message if the seller is online
|
||||
//we send the item to the winner
|
||||
//we send the money to the seller
|
||||
sAuctionMgr.SendAuctionSuccessfulMail(auction);
|
||||
sAuctionMgr.SendAuctionWonMail(auction);
|
||||
sAuctionMgr.SendAuctionSuccessfulMail(auction, trans);
|
||||
sAuctionMgr.SendAuctionWonMail(auction, trans);
|
||||
sScriptMgr.OnAuctionSuccessful(this, auction);
|
||||
}
|
||||
|
||||
///- In any case clear the auction
|
||||
CharacterDatabase.BeginTransaction();
|
||||
auction->DeleteFromDB();
|
||||
uint32 item_template = auction->item_template;
|
||||
sAuctionMgr.RemoveAItem(auction->item_guidlow);
|
||||
|
||||
///- In any case clear the auction
|
||||
auction->DeleteFromDB(trans);
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
RemoveAuction(auction, item_template);
|
||||
CharacterDatabase.CommitTransaction();
|
||||
sAuctionMgr.RemoveAItem(auction->item_guidlow);
|
||||
}
|
||||
while (result->NextRow());
|
||||
}
|
||||
|
||||
void AuctionHouseObject::BuildListBidderItems(WorldPacket& data, Player* player, uint32& count, uint32& totalcount)
|
||||
@@ -746,16 +787,14 @@ uint32 AuctionEntry::GetAuctionOutBid() const
|
||||
return outbid;
|
||||
}
|
||||
|
||||
void AuctionEntry::DeleteFromDB() const
|
||||
void AuctionEntry::DeleteFromDB(SQLTransaction& trans) const
|
||||
{
|
||||
//No SQL injection (Id is integer)
|
||||
CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE id = '%u'",Id);
|
||||
trans->PAppend("DELETE FROM auctionhouse WHERE id = '%u'",Id);
|
||||
}
|
||||
|
||||
void AuctionEntry::SaveToDB() const
|
||||
void AuctionEntry::SaveToDB(SQLTransaction& trans) const
|
||||
{
|
||||
//No SQL injection (no strings)
|
||||
CharacterDatabase.PExecute("INSERT INTO auctionhouse (id,auctioneerguid,itemguid,item_template,itemowner,buyoutprice,time,buyguid,lastbid,startbid,deposit) "
|
||||
trans->PAppend("INSERT INTO auctionhouse (id,auctioneerguid,itemguid,item_template,itemowner,buyoutprice,time,buyguid,lastbid,startbid,deposit) "
|
||||
"VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '" UI64FMTD "', '%u', '%u', '%u', '%u')",
|
||||
Id, auctioneer, item_guidlow, item_template, owner, buyout, (uint64)expire_time, bidder, bid, startbid, deposit);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user