[11284] Implement prepared statements for INSERT+DELETE+UPDATE SQL requests. Should improve player save performance + lower MySQL server CPU usage.

Note: PostgreSQL does not have prepared statements implemented using native APIs.

Huge thanks to Undergarun, kero99 and Vinolentus.

Signed-off-by: Ambal <pogrebniak@gala.net>
This commit is contained in:
Ambal 2011-03-25 21:52:59 +02:00
parent d9374d936f
commit 40ef9cbf2f
24 changed files with 1823 additions and 488 deletions

View file

@ -295,40 +295,58 @@ void Item::SaveToDB()
{
case ITEM_NEW:
{
std::string text = m_text;
CharacterDatabase.escape_string(text);
CharacterDatabase.PExecute( "DELETE FROM item_instance WHERE guid = '%u'", guid );
static SqlStatementID delItem ;
static SqlStatementID insItem ;
SqlStatement stmt = CharacterDatabase.CreateStatement(delItem, "DELETE FROM item_instance WHERE guid = ?");
stmt.PExecute(guid);
std::ostringstream ss;
ss << "INSERT INTO item_instance (guid,owner_guid,data,text) VALUES (" << guid << "," << GetOwnerGuid().GetCounter() << ",'";
for(uint16 i = 0; i < m_valuesCount; ++i )
ss << GetUInt32Value(i) << " ";
ss << "', '" << text << "')";
CharacterDatabase.Execute( ss.str().c_str() );
stmt = CharacterDatabase.CreateStatement(insItem, "INSERT INTO item_instance (guid,owner_guid,data,text) VALUES (?, ?, ?, ?)");
stmt.PExecute(guid, GetOwnerGuid().GetCounter(), ss.str().c_str(), m_text.c_str());
} break;
case ITEM_CHANGED:
{
std::string text = m_text;
CharacterDatabase.escape_string(text);
static SqlStatementID updInstance ;
static SqlStatementID updGifts ;
SqlStatement stmt = CharacterDatabase.CreateStatement(updInstance, "UPDATE item_instance SET data = ?, owner_guid = ?, text = ? WHERE guid = ?");
std::ostringstream ss;
ss << "UPDATE item_instance SET data = '";
for(uint16 i = 0; i < m_valuesCount; ++i )
ss << GetUInt32Value(i) << " ";
ss << "', owner_guid = '" << GetOwnerGuid().GetCounter();
ss << "', text = '" << text << "' WHERE guid = '" << guid << "'";
CharacterDatabase.Execute( ss.str().c_str() );
stmt.PExecute(ss.str().c_str(), GetOwnerGuid().GetCounter(), m_text.c_str(), guid);
if (HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED))
CharacterDatabase.PExecute("UPDATE character_gifts SET guid = '%u' WHERE item_guid = '%u'", GetOwnerGuid().GetCounter(), GetGUIDLow());
{
stmt = CharacterDatabase.CreateStatement(updGifts, "UPDATE character_gifts SET guid = ? WHERE item_guid = ?");
stmt.PExecute(GetOwnerGuid().GetCounter(), GetGUIDLow());
}
} break;
case ITEM_REMOVED:
{
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", guid);
static SqlStatementID delInst ;
static SqlStatementID delGifts ;
static SqlStatementID delLoot ;
SqlStatement stmt = CharacterDatabase.CreateStatement(delInst, "DELETE FROM item_instance WHERE guid = ?");
stmt.PExecute(guid);
if (HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED))
CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", GetGUIDLow());
{
stmt = CharacterDatabase.CreateStatement(delGifts, "DELETE FROM character_gifts WHERE item_guid = ?");
stmt.PExecute(GetGUIDLow());
}
if (HasSavedLoot())
CharacterDatabase.PExecute("DELETE FROM item_loot WHERE guid = '%u'", GetGUIDLow());
{
stmt = CharacterDatabase.CreateStatement(delLoot, "DELETE FROM item_loot WHERE guid = ?");
stmt.PExecute(GetGUIDLow());
}
delete this;
return;
@ -338,17 +356,28 @@ void Item::SaveToDB()
}
if (m_lootState == ITEM_LOOT_CHANGED || m_lootState == ITEM_LOOT_REMOVED)
CharacterDatabase.PExecute("DELETE FROM item_loot WHERE guid = '%u'", GetGUIDLow());
{
static SqlStatementID delLoot ;
SqlStatement stmt = CharacterDatabase.CreateStatement(delLoot, "DELETE FROM item_loot WHERE guid = ?");
stmt.PExecute(GetGUIDLow());
}
if (m_lootState == ITEM_LOOT_NEW || m_lootState == ITEM_LOOT_CHANGED)
{
if(Player* owner = GetOwner())
{
static SqlStatementID saveGold ;
static SqlStatementID saveLoot ;
// save money as 0 itemid data
if (loot.gold)
CharacterDatabase.PExecute("INSERT INTO item_loot (guid,owner_guid,itemid,amount,suffix,property) "
"VALUES (%u, %u, 0, %u, 0, 0)",
GetGUIDLow(), owner->GetGUIDLow(), loot.gold);
{
SqlStatement stmt = CharacterDatabase.CreateStatement(saveGold, "INSERT INTO item_loot (guid,owner_guid,itemid,amount,suffix,property) VALUES (?, ?, 0, ?, 0, 0)");
stmt.PExecute(GetGUIDLow(), owner->GetGUIDLow(), loot.gold);
}
SqlStatement stmt = CharacterDatabase.CreateStatement(saveLoot, "INSERT INTO item_loot (guid,owner_guid,itemid,amount,suffix,property) VALUES (?, ?, ?, ?, ?, ?)");
// save items and quest items (at load its all will added as normal, but this not important for item loot case)
for (size_t i = 0; i < loot.GetMaxSlotInLootFor(owner); ++i)
@ -363,9 +392,14 @@ void Item::SaveToDB()
if (!qitem && item->is_blocked)
continue;
CharacterDatabase.PExecute("INSERT INTO item_loot (guid,owner_guid,itemid,amount,suffix,property) "
"VALUES (%u, %u, %u, %u, %u, %i)",
GetGUIDLow(), owner->GetGUIDLow(), item->itemid, item->count, item->randomSuffix, item->randomPropertyId);
stmt.addUInt32(GetGUIDLow());
stmt.addUInt32(owner->GetGUIDLow());
stmt.addUInt32(item->itemid);
stmt.addUInt8(item->count);
stmt.addUInt32(item->randomSuffix);
stmt.addInt32(item->randomPropertyId);
stmt.Execute();
}
}
@ -452,20 +486,28 @@ bool Item::LoadFromDB(uint32 guidLow, Field *fields, ObjectGuid ownerGuid)
RemoveFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED);
need_save = true;
static SqlStatementID delGifts ;
// also cleanup for sure gift table
CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", GetGUIDLow());
SqlStatement stmt = CharacterDatabase.CreateStatement(delGifts, "DELETE FROM character_gifts WHERE item_guid = ?");
stmt.PExecute(GetGUIDLow());
}
}
if (need_save) // normal item changed state set not work at loading
{
static SqlStatementID updItem ;
SqlStatement stmt = CharacterDatabase.CreateStatement(updItem, "UPDATE item_instance SET data = ?, owner_guid = ? WHERE guid = ?");
std::ostringstream ss;
ss << "UPDATE item_instance SET data = '";
for(uint16 i = 0; i < m_valuesCount; ++i )
ss << GetUInt32Value(i) << " ";
ss << "', owner_guid = '" << GetOwnerGuid().GetCounter() << "' WHERE guid = '" << guidLow << "'";
CharacterDatabase.Execute( ss.str().c_str() );
stmt.addString(ss);
stmt.addUInt32(GetOwnerGuid().GetCounter());
stmt.addUInt32(guidLow);
stmt.Execute();
}
return true;
@ -504,12 +546,18 @@ void Item::LoadLootFromDB(Field *fields)
void Item::DeleteFromDB()
{
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'",GetGUIDLow());
static SqlStatementID delItem ;
SqlStatement stmt = CharacterDatabase.CreateStatement(delItem, "DELETE FROM item_instance WHERE guid = ?");
stmt.PExecute(GetGUIDLow());
}
void Item::DeleteFromInventoryDB()
{
CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'",GetGUIDLow());
static SqlStatementID delInv ;
SqlStatement stmt = CharacterDatabase.CreateStatement(delInv, "DELETE FROM character_inventory WHERE item = ?");
stmt.PExecute(GetGUIDLow());
}
ItemPrototype const *Item::GetProto() const