aboutsummaryrefslogtreecommitdiff
path: root/src/shared/Database
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/Database')
-rw-r--r--src/shared/Database/DBCStores.cpp642
-rw-r--r--src/shared/Database/DBCStores.h202
-rw-r--r--src/shared/Database/DBCStructure.h937
-rw-r--r--src/shared/Database/DBCfmt.cpp78
-rw-r--r--src/shared/Database/Database.cpp171
-rw-r--r--src/shared/Database/Database.h113
-rw-r--r--src/shared/Database/DatabaseEnv.h52
-rw-r--r--src/shared/Database/DatabaseImpl.h146
-rw-r--r--src/shared/Database/DatabaseMysql.cpp408
-rw-r--r--src/shared/Database/DatabaseMysql.h77
-rw-r--r--src/shared/Database/DatabasePostgre.cpp345
-rw-r--r--src/shared/Database/DatabasePostgre.h75
-rw-r--r--src/shared/Database/DatabaseSqlite.cpp101
-rw-r--r--src/shared/Database/DatabaseSqlite.h43
-rw-r--r--src/shared/Database/Field.cpp65
-rw-r--r--src/shared/Database/Field.h75
-rw-r--r--src/shared/Database/Makefile.am62
-rw-r--r--src/shared/Database/MySQLDelayThread.h30
-rw-r--r--src/shared/Database/PGSQLDelayThread.h30
-rw-r--r--src/shared/Database/QueryResult.h64
-rw-r--r--src/shared/Database/QueryResultMysql.cpp110
-rw-r--r--src/shared/Database/QueryResultMysql.h48
-rw-r--r--src/shared/Database/QueryResultPostgre.cpp139
-rw-r--r--src/shared/Database/QueryResultPostgre.h48
-rw-r--r--src/shared/Database/QueryResultSqlite.cpp96
-rw-r--r--src/shared/Database/QueryResultSqlite.h43
-rw-r--r--src/shared/Database/SQLStorage.cpp191
-rw-r--r--src/shared/Database/SQLStorage.h68
-rw-r--r--src/shared/Database/SqlDelayThread.cpp55
-rw-r--r--src/shared/Database/SqlDelayThread.h48
-rw-r--r--src/shared/Database/SqlOperations.cpp197
-rw-r--r--src/shared/Database/SqlOperations.h121
-rw-r--r--src/shared/Database/dbcfile.cpp243
-rw-r--r--src/shared/Database/dbcfile.h107
34 files changed, 5230 insertions, 0 deletions
diff --git a/src/shared/Database/DBCStores.cpp b/src/shared/Database/DBCStores.cpp
new file mode 100644
index 00000000000..623b9652fb3
--- /dev/null
+++ b/src/shared/Database/DBCStores.cpp
@@ -0,0 +1,642 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "DBCStores.h"
+//#include "DataStore.h"
+#include "Policies/SingletonImp.h"
+#include "Log.h"
+#include "ProgressBar.h"
+
+#include "DBCfmt.cpp"
+
+#include <map>
+
+typedef std::map<uint16,uint32> AreaFlagByAreaID;
+typedef std::map<uint32,uint32> AreaFlagByMapID;
+
+DBCStorage <AreaTableEntry> sAreaStore(AreaTableEntryfmt);
+static AreaFlagByAreaID sAreaFlagByAreaID;
+static AreaFlagByMapID sAreaFlagByMapID; // for instances without generated *.map files
+
+DBCStorage <AreaTriggerEntry> sAreaTriggerStore(AreaTriggerEntryfmt);
+DBCStorage <BankBagSlotPricesEntry> sBankBagSlotPricesStore(BankBagSlotPricesEntryfmt);
+DBCStorage <BattlemasterListEntry> sBattlemasterListStore(BattlemasterListEntryfmt);
+DBCStorage <CharTitlesEntry> sCharTitlesStore(CharTitlesEntryfmt);
+DBCStorage <ChatChannelsEntry> sChatChannelsStore(ChatChannelsEntryfmt);
+DBCStorage <ChrClassesEntry> sChrClassesStore(ChrClassesEntryfmt);
+DBCStorage <ChrRacesEntry> sChrRacesStore(ChrRacesEntryfmt);
+DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore(CreatureDisplayInfofmt);
+DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore(CreatureFamilyfmt);
+DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore(CreatureSpellDatafmt);
+
+DBCStorage <DurabilityQualityEntry> sDurabilityQualityStore(DurabilityQualityfmt);
+DBCStorage <DurabilityCostsEntry> sDurabilityCostsStore(DurabilityCostsfmt);
+
+DBCStorage <EmotesTextEntry> sEmotesTextStore(EmoteEntryfmt);
+
+typedef std::map<uint32,SimpleFactionsList> FactionTeamMap;
+static FactionTeamMap sFactionTeamMap;
+DBCStorage <FactionEntry> sFactionStore(FactionEntryfmt);
+DBCStorage <FactionTemplateEntry> sFactionTemplateStore(FactionTemplateEntryfmt);
+
+DBCStorage <GemPropertiesEntry> sGemPropertiesStore(GemPropertiesEntryfmt);
+
+DBCStorage <GtCombatRatingsEntry> sGtCombatRatingsStore(GtCombatRatingsfmt);
+DBCStorage <GtChanceToMeleeCritBaseEntry> sGtChanceToMeleeCritBaseStore(GtChanceToMeleeCritBasefmt);
+DBCStorage <GtChanceToMeleeCritEntry> sGtChanceToMeleeCritStore(GtChanceToMeleeCritfmt);
+DBCStorage <GtChanceToSpellCritBaseEntry> sGtChanceToSpellCritBaseStore(GtChanceToSpellCritBasefmt);
+DBCStorage <GtChanceToSpellCritEntry> sGtChanceToSpellCritStore(GtChanceToSpellCritfmt);
+DBCStorage <GtOCTRegenHPEntry> sGtOCTRegenHPStore(GtOCTRegenHPfmt);
+//DBCStorage <GtOCTRegenMPEntry> sGtOCTRegenMPStore(GtOCTRegenMPfmt); -- not used currently
+DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore(GtRegenHPPerSptfmt);
+DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore(GtRegenMPPerSptfmt);
+DBCStorage <ItemEntry> sItemStore(Itemfmt);
+//DBCStorage <ItemCondExtCostsEntry> sItemCondExtCostsStore(ItemCondExtCostsEntryfmt);
+//DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore(ItemDisplayTemplateEntryfmt); -- not used currently
+DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore(ItemExtendedCostEntryfmt);
+DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore(ItemRandomPropertiesfmt);
+DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore(ItemRandomSuffixfmt);
+DBCStorage <ItemSetEntry> sItemSetStore(ItemSetEntryfmt);
+
+DBCStorage <LockEntry> sLockStore(LockEntryfmt);
+
+DBCStorage <MailTemplateEntry> sMailTemplateStore(MailTemplateEntryfmt);
+DBCStorage <MapEntry> sMapStore(MapEntryfmt);
+
+DBCStorage <QuestSortEntry> sQuestSortStore(QuestSortEntryfmt);
+
+DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore(RandomPropertiesPointsfmt);
+
+DBCStorage <SkillLineEntry> sSkillLineStore(SkillLinefmt);
+DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore(SkillLineAbilityfmt);
+
+DBCStorage <SoundEntriesEntry> sSoundEntriesStore(SoundEntriesfmt);
+
+DBCStorage <SpellItemEnchantmentEntry> sSpellItemEnchantmentStore(SpellItemEnchantmentfmt);
+DBCStorage <SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionStore(SpellItemEnchantmentConditionfmt);
+DBCStorage <SpellEntry> sSpellStore(SpellEntryfmt);
+SpellCategoryStore sSpellCategoryStore;
+PetFamilySpellsStore sPetFamilySpellsStore;
+
+DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore(SpellCastTimefmt);
+DBCStorage <SpellDurationEntry> sSpellDurationStore(SpellDurationfmt);
+DBCStorage <SpellFocusObjectEntry> sSpellFocusObjectStore(SpellFocusObjectfmt);
+DBCStorage <SpellRadiusEntry> sSpellRadiusStore(SpellRadiusfmt);
+DBCStorage <SpellRangeEntry> sSpellRangeStore(SpellRangefmt);
+DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore(SpellShapeshiftfmt);
+DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore(StableSlotPricesfmt);
+DBCStorage <TalentEntry> sTalentStore(TalentEntryfmt);
+TalentSpellPosMap sTalentSpellPosMap;
+DBCStorage <TalentTabEntry> sTalentTabStore(TalentTabEntryfmt);
+
+// store absolute bit position for first rank for talent inspect
+typedef std::map<uint32,uint32> TalentInspectMap;
+static TalentInspectMap sTalentPosInInspect;
+static TalentInspectMap sTalentTabSizeInInspect;
+static uint32 sTalentTabPages[12/*MAX_CLASSES*/][3];
+
+DBCStorage <TaxiNodesEntry> sTaxiNodesStore(TaxiNodesEntryfmt);
+TaxiMask sTaxiNodesMask;
+
+// DBC used only for initialization sTaxiPathSetBySource at startup.
+TaxiPathSetBySource sTaxiPathSetBySource;
+DBCStorage <TaxiPathEntry> sTaxiPathStore(TaxiPathEntryfmt);
+
+// DBC used only for initialization sTaxiPathSetBySource at startup.
+TaxiPathNodesByPath sTaxiPathNodesByPath;
+struct TaxiPathNodeEntry
+{
+ uint32 path;
+ uint32 index;
+ uint32 mapid;
+ float x;
+ float y;
+ float z;
+ uint32 actionFlag;
+ uint32 delay;
+};
+static DBCStorage <TaxiPathNodeEntry> sTaxiPathNodeStore(TaxiPathNodeEntryfmt);
+
+DBCStorage <TotemCategoryEntry> sTotemCategoryStore(TotemCategoryEntryfmt);
+
+DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore(WorldMapAreaEntryfmt);
+DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore(WorldSafeLocsEntryfmt);
+
+typedef std::list<std::string> StoreProblemList;
+
+static bool LoadDBC_assert_print(uint32 fsize,uint32 rsize, std::string filename)
+{
+ sLog.outError("ERROR: Size of '%s' setted by format string (%u) not equal size of C++ structure (%u).",filename.c_str(),fsize,rsize);
+
+ // assert must fail after function call
+ return false;
+}
+
+template<class T>
+inline void LoadDBC(uint32& availableDbcLocales,barGoLink& bar, StoreProblemList& errlist, DBCStorage<T>& storage, std::string dbc_path, std::string filename)
+{
+ // compatibility format and C++ structure sizes
+ assert(DBCFile::GetFormatRecordSize(storage.GetFormat()) == sizeof(T) || LoadDBC_assert_print(DBCFile::GetFormatRecordSize(storage.GetFormat()),sizeof(T),filename));
+
+ std::string dbc_filename = dbc_path + filename;
+ if(storage.Load(dbc_filename.c_str()))
+ {
+ bar.step();
+ for(uint8 i = 0; i < MAX_LOCALE; ++i)
+ {
+ if(!(availableDbcLocales & (1 << i)))
+ continue;
+
+ std::string dbc_filename_loc = dbc_path + localeNames[i] + "/" + filename;
+ if(!storage.LoadStringsFrom(dbc_filename_loc.c_str()))
+ availableDbcLocales &= ~(1<<i); // mark as not available for speedup next checks
+ }
+ }
+ else
+ {
+ // sort problematic dbc to (1) non compatible and (2) non-existed
+ FILE * f=fopen(dbc_filename.c_str(),"rb");
+ if(f)
+ {
+ char buf[100];
+ snprintf(buf,100," (exist, but have %d fields instead %d) Wrong client version DBC file?",storage.GetFieldCount(),strlen(storage.GetFormat()));
+ errlist.push_back(dbc_filename + buf);
+ fclose(f);
+ }
+ else
+ errlist.push_back(dbc_filename);
+ }
+}
+
+void LoadDBCStores(std::string dataPath)
+{
+ std::string dbcPath = dataPath+"dbc/";
+
+ const uint32 DBCFilesCount = 56;
+
+ barGoLink bar( DBCFilesCount );
+
+ StoreProblemList bad_dbc_files;
+ uint32 availableDbcLocales = 0xFFFFFFFF;
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAreaStore, dbcPath,"AreaTable.dbc");
+
+ // must be after sAreaStore loading
+ for(uint32 i = 0; i < sAreaStore.GetNumRows(); ++i) // areaflag numbered from 0
+ {
+ if(AreaTableEntry const* area = sAreaStore.LookupEntry(i))
+ {
+ // fill AreaId->DBC records
+ sAreaFlagByAreaID.insert(AreaFlagByAreaID::value_type(uint16(area->ID),area->exploreFlag));
+
+ // fill MapId->DBC records ( skip sub zones and continents )
+ if(area->zone==0 && area->mapid != 0 && area->mapid != 1 && area->mapid != 530 )
+ sAreaFlagByMapID.insert(AreaFlagByMapID::value_type(area->mapid,area->exploreFlag));
+ }
+ }
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAreaTriggerStore, dbcPath,"AreaTrigger.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sBankBagSlotPricesStore, dbcPath,"BankBagSlotPrices.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sBattlemasterListStore, dbcPath,"BattlemasterList.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCharTitlesStore, dbcPath,"CharTitles.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChatChannelsStore, dbcPath,"ChatChannels.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChrClassesStore, dbcPath,"ChrClasses.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChrRacesStore, dbcPath,"ChrRaces.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureDisplayInfoStore, dbcPath,"CreatureDisplayInfo.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureFamilyStore, dbcPath,"CreatureFamily.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureSpellDataStore, dbcPath,"CreatureSpellData.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sDurabilityCostsStore, dbcPath,"DurabilityCosts.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sDurabilityQualityStore, dbcPath,"DurabilityQuality.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sEmotesTextStore, dbcPath,"EmotesText.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sFactionStore, dbcPath,"Faction.dbc");
+ for (uint32 i=0;i<sFactionStore.GetNumRows(); ++i)
+ {
+ FactionEntry const * faction = sFactionStore.LookupEntry(i);
+ if (faction && faction->team)
+ {
+ SimpleFactionsList &flist = sFactionTeamMap[faction->team];
+ flist.push_back(i);
+ }
+ }
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sFactionTemplateStore, dbcPath,"FactionTemplate.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGemPropertiesStore, dbcPath,"GemProperties.dbc");
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtCombatRatingsStore, dbcPath,"gtCombatRatings.dbc");
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtChanceToMeleeCritBaseStore, dbcPath,"gtChanceToMeleeCritBase.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtChanceToMeleeCritStore, dbcPath,"gtChanceToMeleeCrit.dbc");
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtChanceToSpellCritBaseStore, dbcPath,"gtChanceToSpellCritBase.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtChanceToSpellCritStore, dbcPath,"gtChanceToSpellCrit.dbc");
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtOCTRegenHPStore, dbcPath,"gtOCTRegenHP.dbc");
+ //LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtOCTRegenMPStore, dbcPath,"gtOCTRegenMP.dbc"); -- not used currently
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtRegenHPPerSptStore, dbcPath,"gtRegenHPPerSpt.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtRegenMPPerSptStore, dbcPath,"gtRegenMPPerSpt.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemStore, dbcPath,"Item.dbc");
+ //LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemDisplayInfoStore, dbcPath,"ItemDisplayInfo.dbc"); -- not used currently
+ //LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemCondExtCostsStore, dbcPath,"ItemCondExtCosts.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemExtendedCostStore, dbcPath,"ItemExtendedCost.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemRandomPropertiesStore,dbcPath,"ItemRandomProperties.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemRandomSuffixStore, dbcPath,"ItemRandomSuffix.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemSetStore, dbcPath,"ItemSet.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sLockStore, dbcPath,"Lock.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMailTemplateStore, dbcPath,"MailTemplate.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMapStore, dbcPath,"Map.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sQuestSortStore, dbcPath,"QuestSort.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sRandomPropertiesPointsStore, dbcPath,"RandPropPoints.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSkillLineStore, dbcPath,"SkillLine.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSkillLineAbilityStore, dbcPath,"SkillLineAbility.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSoundEntriesStore, dbcPath,"SoundEntries.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellStore, dbcPath,"Spell.dbc");
+ for(uint32 i = 1; i < sSpellStore.GetNumRows(); ++i)
+ {
+ SpellEntry const * spell = sSpellStore.LookupEntry(i);
+ if(spell && spell->Category)
+ sSpellCategoryStore[spell->Category].insert(i);
+
+ // DBC not support uint64 fields but SpellEntry have SpellFamilyFlags mapped at 2 uint32 fields
+ // uint32 field already converted to bigendian if need, but must be swapped for correct uint64 bigendian view
+ #if MANGOS_ENDIAN == MANGOS_BIGENDIAN
+ std::swap(*((uint32*)(&spell->SpellFamilyFlags)),*(((uint32*)(&spell->SpellFamilyFlags))+1));
+ #endif
+ }
+
+ for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
+ {
+ SkillLineAbilityEntry const *skillLine = sSkillLineAbilityStore.LookupEntry(j);
+
+ if(!skillLine)
+ continue;
+
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->spellId);
+
+ if(spellInfo && (spellInfo->Attributes & 0x1D0) == 0x1D0)
+ {
+ for (unsigned int i = 1; i < sCreatureFamilyStore.GetNumRows(); ++i)
+ {
+ CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(i);
+ if(!cFamily)
+ continue;
+
+ if(skillLine->skillId != cFamily->skillLine && skillLine->skillId != cFamily->skillLine2)
+ continue;
+
+ sPetFamilySpellsStore[i].insert(spellInfo->Id);
+ }
+ }
+ }
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellCastTimesStore, dbcPath,"SpellCastTimes.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellDurationStore, dbcPath,"SpellDuration.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellFocusObjectStore, dbcPath,"SpellFocusObject.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellItemEnchantmentStore,dbcPath,"SpellItemEnchantment.dbc");
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellItemEnchantmentConditionStore,dbcPath,"SpellItemEnchantmentCondition.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellRadiusStore, dbcPath,"SpellRadius.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellRangeStore, dbcPath,"SpellRange.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellShapeshiftStore, dbcPath,"SpellShapeshiftForm.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sStableSlotPricesStore, dbcPath,"StableSlotPrices.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTalentStore, dbcPath,"Talent.dbc");
+
+ // create talent spells set
+ for (unsigned int i = 0; i < sTalentStore.GetNumRows(); ++i)
+ {
+ TalentEntry const *talentInfo = sTalentStore.LookupEntry(i);
+ if (!talentInfo) continue;
+ for (int j = 0; j < 5; j++)
+ if(talentInfo->RankID[j])
+ sTalentSpellPosMap[talentInfo->RankID[j]] = TalentSpellPos(i,j);
+ }
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTalentTabStore, dbcPath,"TalentTab.dbc");
+
+ // preper fast data access to bit pos of talent ranks for use at inspecting
+ {
+ // fill table by amount of talent ranks and fill sTalentTabBitSizeInInspect
+ // store in with (row,col,talent)->size key for correct sorting by (row,col)
+ typedef std::map<uint32,uint32> TalentBitSize;
+ TalentBitSize sTalentBitSize;
+ for(uint32 i = 1; i < sTalentStore.GetNumRows(); ++i)
+ {
+ TalentEntry const *talentInfo = sTalentStore.LookupEntry(i);
+ if (!talentInfo) continue;
+
+ TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentInfo->TalentTab );
+ if(!talentTabInfo)
+ continue;
+
+ // find talent rank
+ uint32 curtalent_maxrank = 0;
+ for(uint32 k = 5; k > 0; --k)
+ {
+ if(talentInfo->RankID[k-1])
+ {
+ curtalent_maxrank = k;
+ break;
+ }
+ }
+
+ sTalentBitSize[(talentInfo->Row<<24) + (talentInfo->Col<<16)+talentInfo->TalentID] = curtalent_maxrank;
+ sTalentTabSizeInInspect[talentInfo->TalentTab] += curtalent_maxrank;
+ }
+
+ // now have all max ranks (and then bit amount used for store talent ranks in inspect)
+ for(uint32 talentTabId = 1; talentTabId < sTalentTabStore.GetNumRows(); ++talentTabId)
+ {
+ TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentTabId );
+ if(!talentTabInfo)
+ continue;
+
+ // store class talent tab pages
+ uint32 cls = 1;
+ for(uint32 m=1;!(m & talentTabInfo->ClassMask) && cls < 12 /*MAX_CLASSES*/;m <<=1, ++cls) {}
+
+ sTalentTabPages[cls][talentTabInfo->tabpage]=talentTabId;
+
+ // add total amount bits for first rank starting from talent tab first talent rank pos.
+ uint32 pos = 0;
+ for(TalentBitSize::iterator itr = sTalentBitSize.begin(); itr != sTalentBitSize.end(); ++itr)
+ {
+ uint32 talentId = itr->first & 0xFFFF;
+ TalentEntry const *talentInfo = sTalentStore.LookupEntry( talentId );
+ if(!talentInfo)
+ continue;
+
+ if(talentInfo->TalentTab != talentTabId)
+ continue;
+
+ sTalentPosInInspect[talentId] = pos;
+ pos+= itr->second;
+ }
+ }
+ }
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTaxiNodesStore, dbcPath,"TaxiNodes.dbc");
+
+ // Initialize global taxinodes mask
+ memset(sTaxiNodesMask,0,sizeof(sTaxiNodesMask));
+ for(uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i)
+ {
+ if(sTaxiNodesStore.LookupEntry(i))
+ {
+ uint8 field = (uint8)((i - 1) / 32);
+ uint32 submask = 1<<((i-1)%32);
+ sTaxiNodesMask[field] |= submask;
+ }
+ }
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTaxiPathStore, dbcPath,"TaxiPath.dbc");
+ for(uint32 i = 1; i < sTaxiPathStore.GetNumRows(); ++i)
+ if(TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(i))
+ sTaxiPathSetBySource[entry->from][entry->to] = TaxiPathBySourceAndDestination(entry->ID,entry->price);
+ uint32 pathCount = sTaxiPathStore.GetNumRows();
+
+ //## TaxiPathNode.dbc ## Loaded only for initialization different structures
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTaxiPathNodeStore, dbcPath,"TaxiPathNode.dbc");
+ // Calculate path nodes count
+ std::vector<uint32> pathLength;
+ pathLength.resize(pathCount); // 0 and some other indexes not used
+ for(uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i)
+ if(TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i))
+ ++pathLength[entry->path];
+ // Set path length
+ sTaxiPathNodesByPath.resize(pathCount); // 0 and some other indexes not used
+ for(uint32 i = 1; i < sTaxiPathNodesByPath.size(); ++i)
+ sTaxiPathNodesByPath[i].resize(pathLength[i]);
+ // fill data
+ for(uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i)
+ if(TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i))
+ sTaxiPathNodesByPath[entry->path][entry->index] = TaxiPathNode(entry->mapid,entry->x,entry->y,entry->z,entry->actionFlag,entry->delay);
+ sTaxiPathNodeStore.Clear();
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTotemCategoryStore, dbcPath,"TotemCategory.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWorldMapAreaStore, dbcPath,"WorldMapArea.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWorldSafeLocsStore, dbcPath,"WorldSafeLocs.dbc");
+
+ // error checks
+ if(bad_dbc_files.size() >= DBCFilesCount )
+ {
+ sLog.outError("\nIncorrect DataDir value in mangosd.conf or ALL required *.dbc files (%d) not found by path: %sdbc",DBCFilesCount,dataPath.c_str());
+ exit(1);
+ }
+ else if(!bad_dbc_files.empty() )
+ {
+ std::string str;
+ for(std::list<std::string>::iterator i = bad_dbc_files.begin(); i != bad_dbc_files.end(); ++i)
+ str += *i + "\n";
+
+ sLog.outError("\nSome required *.dbc files (%u from %d) not found or not compatible:\n%s",bad_dbc_files.size(),DBCFilesCount,str.c_str());
+ exit(1);
+ }
+
+ // check at up-to-date DBC files (53085 is last added spell in 2.4.3)
+ // check at up-to-date DBC files (17514 is last ID in SkillLineAbilities in 2.4.3)
+ // check at up-to-date DBC files (598 is last map added in 2.4.3)
+ // check at up-to-date DBC files (1127 is last gem property added in 2.4.3)
+ // check at up-to-date DBC files (2425 is last item extended cost added in 2.4.3)
+ // check at up-to-date DBC files (71 is last char title added in 2.4.3)
+ // check at up-to-date DBC files (1768 is last area added in 2.4.3)
+ if( !sSpellStore.LookupEntry(53085) ||
+ !sSkillLineAbilityStore.LookupEntry(17514) ||
+ !sMapStore.LookupEntry(598) ||
+ !sGemPropertiesStore.LookupEntry(1127) ||
+ !sItemExtendedCostStore.LookupEntry(2425) ||
+ !sCharTitlesStore.LookupEntry(71) ||
+ !sAreaStore.LookupEntry(1768) )
+ {
+ sLog.outError("\nYou have _outdated_ DBC files. Please extract correct versions from current using client.");
+ exit(1);
+ }
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %d data stores", DBCFilesCount );
+ sLog.outString();
+}
+
+SimpleFactionsList const* GetFactionTeamList(uint32 faction)
+{
+ FactionTeamMap::const_iterator itr = sFactionTeamMap.find(faction);
+ if(itr==sFactionTeamMap.end())
+ return NULL;
+ return &itr->second;
+}
+
+char* GetPetName(uint32 petfamily, uint32 dbclang)
+{
+ if(!petfamily)
+ return NULL;
+ CreatureFamilyEntry const *pet_family = sCreatureFamilyStore.LookupEntry(petfamily);
+ if(!pet_family)
+ return NULL;
+ return pet_family->Name[dbclang]?pet_family->Name[dbclang]:NULL;
+}
+
+TalentSpellPos const* GetTalentSpellPos(uint32 spellId)
+{
+ TalentSpellPosMap::const_iterator itr = sTalentSpellPosMap.find(spellId);
+ if(itr==sTalentSpellPosMap.end())
+ return NULL;
+
+ return &itr->second;
+}
+
+uint32 GetTalentSpellCost(uint32 spellId)
+{
+ if(TalentSpellPos const* pos = GetTalentSpellPos(spellId))
+ return pos->rank+1;
+
+ return 0;
+}
+
+AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id)
+{
+ AreaFlagByAreaID::iterator i = sAreaFlagByAreaID.find(area_id);
+ if(i == sAreaFlagByAreaID.end())
+ return NULL;
+
+ return sAreaStore.LookupEntry(i->second);
+}
+
+AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag,uint32 map_id)
+{
+ if(area_flag)
+ return sAreaStore.LookupEntry(area_flag);
+
+ if(MapEntry const* mapEntry = sMapStore.LookupEntry(map_id))
+ return GetAreaEntryByAreaID(mapEntry->linked_zone);
+
+ return NULL;
+}
+
+uint32 GetAreaFlagByMapId(uint32 mapid)
+{
+ AreaFlagByMapID::iterator i = sAreaFlagByMapID.find(mapid);
+ if(i == sAreaFlagByMapID.end())
+ return 0;
+ else
+ return i->second;
+}
+
+uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId)
+{
+ if(mapid != 530) // speed for most cases
+ return mapid;
+
+ if(WorldMapAreaEntry const* wma = sWorldMapAreaStore.LookupEntry(zoneId))
+ return wma->virtual_map_id >= 0 ? wma->virtual_map_id : wma->map_id;
+
+ return mapid;
+}
+
+ContentLevels GetContentLevelsForMapAndZone(uint32 mapid, uint32 zoneId)
+{
+ mapid = GetVirtualMapForMapAndZone(mapid,zoneId);
+ if(mapid < 2)
+ return CONTENT_1_60;
+
+ MapEntry const* mapEntry = sMapStore.LookupEntry(mapid);
+ return (!mapEntry || !mapEntry->IsExpansionMap()) ? CONTENT_1_60 : CONTENT_61_70;
+}
+
+ChatChannelsEntry const* GetChannelEntryFor(uint32 channel_id)
+{
+ // not sorted, numbering index from 0
+ for(uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i)
+ {
+ ChatChannelsEntry const* ch = sChatChannelsStore.LookupEntry(i);
+ if(ch && ch->ChannelID == channel_id)
+ return ch;
+ }
+ return NULL;
+}
+
+bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredTotemCategoryId)
+{
+ if(requiredTotemCategoryId==0)
+ return true;
+ if(itemTotemCategoryId==0)
+ return false;
+
+ TotemCategoryEntry const* itemEntry = sTotemCategoryStore.LookupEntry(itemTotemCategoryId);
+ if(!itemEntry)
+ return false;
+ TotemCategoryEntry const* reqEntry = sTotemCategoryStore.LookupEntry(requiredTotemCategoryId);
+ if(!reqEntry)
+ return false;
+
+ if(itemEntry->categoryType!=reqEntry->categoryType)
+ return false;
+
+ return (itemEntry->categoryMask & reqEntry->categoryMask)==reqEntry->categoryMask;
+}
+
+void Zone2MapCoordinates(float& x,float& y,uint32 zone)
+{
+ WorldMapAreaEntry const* maEntry = sWorldMapAreaStore.LookupEntry(zone);
+
+ // if not listed then map coordinates (instance)
+ if(!maEntry)
+ return;
+
+ std::swap(x,y); // at client map coords swapped
+ x = x*((maEntry->x2-maEntry->x1)/100)+maEntry->x1;
+ y = y*((maEntry->y2-maEntry->y1)/100)+maEntry->y1; // client y coord from top to down
+}
+
+void Map2ZoneCoordinates(float& x,float& y,uint32 zone)
+{
+ WorldMapAreaEntry const* maEntry = sWorldMapAreaStore.LookupEntry(zone);
+
+ // if not listed then map coordinates (instance)
+ if(!maEntry)
+ return;
+
+ x = (x-maEntry->x1)/((maEntry->x2-maEntry->x1)/100);
+ y = (y-maEntry->y1)/((maEntry->y2-maEntry->y1)/100); // client y coord from top to down
+ std::swap(x,y); // client have map coords swapped
+}
+
+uint32 GetTalentInspectBitPosInTab(uint32 talentId)
+{
+ TalentInspectMap::const_iterator itr = sTalentPosInInspect.find(talentId);
+ if(itr == sTalentPosInInspect.end())
+ return 0;
+
+ return itr->second;
+}
+
+uint32 GetTalentTabInspectBitSize(uint32 talentTabId)
+{
+ TalentInspectMap::const_iterator itr = sTalentTabSizeInInspect.find(talentTabId);
+ if(itr == sTalentTabSizeInInspect.end())
+ return 0;
+
+ return itr->second;
+}
+
+uint32 const* GetTalentTabPages(uint32 cls)
+{
+ return sTalentTabPages[cls];
+}
+
+// script support functions
+MANGOS_DLL_SPEC DBCStorage <SoundEntriesEntry> const* GetSoundEntriesStore() { return &sSoundEntriesStore; }
+MANGOS_DLL_SPEC DBCStorage <SpellEntry> const* GetSpellStore() { return &sSpellStore; }
+MANGOS_DLL_SPEC DBCStorage <SpellRangeEntry> const* GetSpellRangeStore() { return &sSpellRangeStore; }
diff --git a/src/shared/Database/DBCStores.h b/src/shared/Database/DBCStores.h
new file mode 100644
index 00000000000..e1d05298695
--- /dev/null
+++ b/src/shared/Database/DBCStores.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef DBCSTORES_H
+#define DBCSTORES_H
+
+#include "Common.h"
+//#include "DataStore.h"
+#include "dbcfile.h"
+#include "DBCStructure.h"
+
+#include <list>
+
+typedef std::list<uint32> SimpleFactionsList;
+
+SimpleFactionsList const* GetFactionTeamList(uint32 faction);
+char* GetPetName(uint32 petfamily, uint32 dbclang);
+uint32 GetTalentSpellCost(uint32 spellId);
+TalentSpellPos const* GetTalentSpellPos(uint32 spellId);
+
+AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id);
+AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag,uint32 map_id);
+uint32 GetAreaFlagByMapId(uint32 mapid);
+
+uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId);
+
+enum ContentLevels
+{
+ CONTENT_1_60 = 0,
+ CONTENT_61_70
+};
+ContentLevels GetContentLevelsForMapAndZone(uint32 mapid, uint32 zoneId);
+
+ChatChannelsEntry const* GetChannelEntryFor(uint32 channel_id);
+
+bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredTotemCategoryId);
+
+void Zone2MapCoordinates(float& x,float& y,uint32 zone);
+void Map2ZoneCoordinates(float& x,float& y,uint32 zone);
+
+uint32 GetTalentInspectBitPosInTab(uint32 talentId);
+uint32 GetTalentTabInspectBitSize(uint32 talentTabId);
+uint32 const* /*[3]*/ GetTalentTabPages(uint32 cls);
+
+template<class T>
+class DBCStorage
+{
+ typedef std::list<char*> StringPoolList;
+ public:
+ explicit DBCStorage(const char *f) : nCount(0), fieldCount(0), fmt(f), indexTable(NULL), m_dataTable(NULL) { }
+ ~DBCStorage() { Clear(); }
+
+ T const* LookupEntry(uint32 id) const { return (id>=nCount)?NULL:indexTable[id]; }
+ uint32 GetNumRows() const { return nCount; }
+ char const* GetFormat() const { return fmt; }
+ uint32 GetFieldCount() const { return fieldCount; }
+
+ bool Load(char const* fn)
+ {
+
+ DBCFile dbc;
+ // Check if load was sucessful, only then continue
+ if(!dbc.Load(fn, fmt))
+ return false;
+
+ fieldCount = dbc.GetCols();
+ m_dataTable = (T*)dbc.AutoProduceData(fmt,nCount,(char**&)indexTable);
+ m_stringPoolList.push_back(dbc.AutoProduceStrings(fmt,(char*)m_dataTable));
+
+ // error in dbc file at loading if NULL
+ return indexTable!=NULL;
+ }
+
+ bool LoadStringsFrom(char const* fn)
+ {
+ // DBC must be already loaded using Load
+ if(!indexTable)
+ return false;
+
+ DBCFile dbc;
+ // Check if load was successful, only then continue
+ if(!dbc.Load(fn, fmt))
+ return false;
+
+ m_stringPoolList.push_back(dbc.AutoProduceStrings(fmt,(char*)m_dataTable));
+
+ return true;
+ }
+
+ void Clear()
+ {
+ if (!indexTable)
+ return;
+
+ delete[] ((char*)indexTable);
+ indexTable = NULL;
+ delete[] ((char*)m_dataTable);
+ m_dataTable = NULL;
+
+ while(!m_stringPoolList.empty())
+ {
+ delete[] m_stringPoolList.front();
+ m_stringPoolList.pop_front();
+ }
+ nCount = 0;
+ }
+
+ private:
+ uint32 nCount;
+ uint32 fieldCount;
+ char const* fmt;
+ T** indexTable;
+ T* m_dataTable;
+ StringPoolList m_stringPoolList;
+};
+
+extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions
+extern DBCStorage <AreaTriggerEntry> sAreaTriggerStore;
+extern DBCStorage <BankBagSlotPricesEntry> sBankBagSlotPricesStore;
+extern DBCStorage <BattlemasterListEntry> sBattlemasterListStore;
+//extern DBCStorage <ChatChannelsEntry> sChatChannelsStore; -- accessed using function, no usable index
+extern DBCStorage <CharTitlesEntry> sCharTitlesStore;
+extern DBCStorage <ChrClassesEntry> sChrClassesStore;
+extern DBCStorage <ChrRacesEntry> sChrRacesStore;
+extern DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore;
+extern DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore;
+extern DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore;
+extern DBCStorage <DurabilityCostsEntry> sDurabilityCostsStore;
+extern DBCStorage <DurabilityQualityEntry> sDurabilityQualityStore;
+extern DBCStorage <EmotesTextEntry> sEmotesTextStore;
+extern DBCStorage <FactionEntry> sFactionStore;
+extern DBCStorage <FactionTemplateEntry> sFactionTemplateStore;
+extern DBCStorage <GemPropertiesEntry> sGemPropertiesStore;
+
+extern DBCStorage <GtCombatRatingsEntry> sGtCombatRatingsStore;
+extern DBCStorage <GtChanceToMeleeCritBaseEntry> sGtChanceToMeleeCritBaseStore;
+extern DBCStorage <GtChanceToMeleeCritEntry> sGtChanceToMeleeCritStore;
+extern DBCStorage <GtChanceToSpellCritBaseEntry> sGtChanceToSpellCritBaseStore;
+extern DBCStorage <GtChanceToSpellCritEntry> sGtChanceToSpellCritStore;
+extern DBCStorage <GtOCTRegenHPEntry> sGtOCTRegenHPStore;
+//extern DBCStorage <GtOCTRegenMPEntry> sGtOCTRegenMPStore; -- not used currently
+extern DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore;
+extern DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore;
+extern DBCStorage <ItemEntry> sItemStore;
+//extern DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore; -- not used currently
+extern DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore;
+extern DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore;
+extern DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore;
+extern DBCStorage <ItemSetEntry> sItemSetStore;
+extern DBCStorage <LockEntry> sLockStore;
+extern DBCStorage <MailTemplateEntry> sMailTemplateStore;
+extern DBCStorage <MapEntry> sMapStore;
+extern DBCStorage <QuestSortEntry> sQuestSortStore;
+extern DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore;
+extern DBCStorage <SkillLineEntry> sSkillLineStore;
+extern DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore;
+extern DBCStorage <SoundEntriesEntry> sSoundEntriesStore;
+extern DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore;
+extern DBCStorage <SpellDurationEntry> sSpellDurationStore;
+extern DBCStorage <SpellFocusObjectEntry> sSpellFocusObjectStore;
+extern DBCStorage <SpellItemEnchantmentEntry> sSpellItemEnchantmentStore;
+extern DBCStorage <SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionStore;
+extern SpellCategoryStore sSpellCategoryStore;
+extern PetFamilySpellsStore sPetFamilySpellsStore;
+extern DBCStorage <SpellRadiusEntry> sSpellRadiusStore;
+extern DBCStorage <SpellRangeEntry> sSpellRangeStore;
+extern DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore;
+extern DBCStorage <SpellEntry> sSpellStore;
+extern DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore;
+extern DBCStorage <TalentEntry> sTalentStore;
+extern DBCStorage <TalentTabEntry> sTalentTabStore;
+extern DBCStorage <TaxiNodesEntry> sTaxiNodesStore;
+extern DBCStorage <TaxiPathEntry> sTaxiPathStore;
+extern TaxiMask sTaxiNodesMask;
+extern TaxiPathSetBySource sTaxiPathSetBySource;
+extern TaxiPathNodesByPath sTaxiPathNodesByPath;
+extern DBCStorage <TotemCategoryEntry> sTotemCategoryStore;
+//extern DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore; -- use Zone2MapCoordinates and Map2ZoneCoordinates
+extern DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore;
+
+void LoadDBCStores(std::string dataPath);
+
+// script support functions
+MANGOS_DLL_SPEC DBCStorage <SoundEntriesEntry> const* GetSoundEntriesStore();
+MANGOS_DLL_SPEC DBCStorage <SpellEntry> const* GetSpellStore();
+MANGOS_DLL_SPEC DBCStorage <SpellRangeEntry> const* GetSpellRangeStore();
+#endif
diff --git a/src/shared/Database/DBCStructure.h b/src/shared/Database/DBCStructure.h
new file mode 100644
index 00000000000..c0370180511
--- /dev/null
+++ b/src/shared/Database/DBCStructure.h
@@ -0,0 +1,937 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef DBCSTRUCTURE_H
+#define DBCSTRUCTURE_H
+
+#include "Platform/Define.h"
+
+#include <map>
+#include <set>
+#include <vector>
+
+// Structures using to access raw DBC data and required packing to portability
+
+// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform
+#if defined( __GNUC__ )
+#pragma pack(1)
+#else
+#pragma pack(push,1)
+#endif
+
+enum AreaTeams
+{
+ AREATEAM_NONE = 0,
+ AREATEAM_ALLY = 2,
+ AREATEAM_HORDE = 4
+};
+
+enum AreaFlags
+{
+ AREA_FLAG_SNOW = 0x00000001, // snow (only Dun Morogh, Naxxramas, Razorfen Downs and Winterspring)
+ AREA_FLAG_UNK1 = 0x00000002, // unknown, (only Naxxramas and Razorfen Downs)
+ AREA_FLAG_UNK2 = 0x00000004, // Only used on development map
+ AREA_FLAG_SLAVE_CAPITAL = 0x00000008, // slave capital city flag?
+ AREA_FLAG_UNK3 = 0x00000010, // unknown
+ AREA_FLAG_SLAVE_CAPITAL2 = 0x00000020, // slave capital city flag?
+ AREA_FLAG_UNK4 = 0x00000040, // many zones have this flag
+ AREA_FLAG_ARENA = 0x00000080, // arena, both instanced and world arenas
+ AREA_FLAG_CAPITAL = 0x00000100, // main capital city flag
+ AREA_FLAG_CITY = 0x00000200, // only for one zone named "City" (where it located?)
+ AREA_FLAG_OUTLAND = 0x00000400, // outland zones? (only Eye of the Storm not have this flag, but have 0x00004000 flag)
+ AREA_FLAG_SANCTUARY = 0x00000800, // sanctuary area (PvP disabled)
+ AREA_FLAG_NEED_FLY = 0x00001000, // only Netherwing Ledge, Socrethar's Seat, Tempest Keep, The Arcatraz, The Botanica, The Mechanar, Sorrow Wing Point, Dragonspine Ridge, Netherwing Mines, Dragonmaw Base Camp, Dragonmaw Skyway
+ AREA_FLAG_UNUSED1 = 0x00002000, // not used now (no area/zones with this flag set in 2.4.2)
+ AREA_FLAG_OUTLAND2 = 0x00004000, // outland zones? (only Circle of Blood Arena not have this flag, but have 0x00000400 flag)
+ AREA_FLAG_PVP = 0x00008000, // pvp objective area? (Death's Door also has this flag although it's no pvp object area)
+ AREA_FLAG_ARENA_INSTANCE = 0x00010000, // used by instanced arenas only
+ AREA_FLAG_UNUSED2 = 0x00020000, // not used now (no area/zones with this flag set in 2.4.2)
+ AREA_FLAG_UNK5 = 0x00040000, // just used for Amani Pass, Hatchet Hills
+ AREA_FLAG_LOWLEVEL = 0x00100000 // used for some starting areas with area_level <=15
+};
+
+enum FactionTemplateFlags
+{
+ FACTION_TEMPLATE_FLAG_CONTESTED_GUARD = 0x00001000, // faction will attack players that were involved in PvP combats
+};
+
+struct AreaTableEntry
+{
+ uint32 ID; // 0
+ uint32 mapid; // 1
+ uint32 zone; // 2 if 0 then it's zone, else it's zone id of this area
+ uint32 exploreFlag; // 3, main index
+ uint32 flags; // 4, unknown value but 312 for all cities
+ // 5-9 unused
+ int32 area_level; // 10
+ char* area_name[16]; // 11-26
+ // 27, string flags, unused
+ uint32 team; // 28
+};
+
+struct AreaTriggerEntry
+{
+ uint32 id; // 0
+ uint32 mapid; // 1
+ float x; // 2
+ float y; // 3
+ float z; // 4
+ float radius; // 5
+ float box_x; // 6 extent x edge
+ float box_y; // 7 extent y edge
+ float box_z; // 8 extent z edge
+ float box_orientation; // 9 extent rotation by about z axis
+};
+
+struct BankBagSlotPricesEntry
+{
+ uint32 ID;
+ uint32 price;
+};
+
+struct BattlemasterListEntry
+{
+ uint32 id; // 0
+ uint32 mapid[3]; // 1-3 mapid
+ // 4-8 unused
+ uint32 type; // 9 (3 - BG, 4 - arena)
+ uint32 minlvl; // 10
+ uint32 maxlvl; // 11
+ uint32 maxplayersperteam; // 12
+ // 13-14 unused
+ char* name[16]; // 15-30
+ // 31 string flag, unused
+ // 32 unused
+};
+
+struct CharTitlesEntry
+{
+ uint32 ID; // 0, title ids, for example in Quest::GetCharTitleId()
+ //uint32 unk1; // 1 flags?
+ //char* name[16]; // 2-17, unused
+ // 18 string flag, unused
+ //char* name2[16]; // 19-34, unused
+ // 35 string flag, unused
+ uint32 bit_index; // 36 used in PLAYER_CHOSEN_TITLE and 1<<index in PLAYER__FIELD_KNOWN_TITLES
+};
+
+struct ChatChannelsEntry
+{
+ uint32 ChannelID; // 0
+ uint32 flags; // 1
+ char* pattern[16]; // 3-18
+ // 19 string flags, unused
+ //char* name[16]; // 20-35 unused
+ // 36 string flag, unused
+};
+
+struct ChrClassesEntry
+{
+ uint32 ClassID; // 0
+ // 1-2, unused
+ uint32 powerType; // 3
+ // 4, unused
+ //char* name[16]; // 5-20 unused
+ // 21 string flag, unused
+ //char* string1[16]; // 21-36 unused
+ // 37 string flag, unused
+ //char* string2[16]; // 38-53 unused
+ // 54 string flag, unused
+ // 55, unused
+ uint32 spellfamily; // 56
+ // 57, unused
+};
+
+struct ChrRacesEntry
+{
+ uint32 RaceID; // 0
+ // 1 unused
+ uint32 FactionID; // 2 facton template id
+ // 3 unused
+ uint32 model_m; // 4
+ uint32 model_f; // 5
+ // 6-7 unused
+ uint32 TeamID; // 8 (7-Alliance 1-Horde)
+ // 9-12 unused
+ uint32 startmovie; // 13 id from CinematicCamera.dbc
+ char* name[16]; // 14-29 used for DBC language detection/selection
+ // 30 string flags, unused
+ //char* string1[16]; // 31-46 used for DBC language detection/selection
+ // 47 string flags, unused
+ //char* string2[16]; // 48-63 used for DBC language detection/selection
+ // 64 string flags, unused
+ // 65-67 unused
+ //uint32 addon // 68 (0 - original race, 1 - tbc addon, ...) unused
+};
+
+struct CreatureDisplayInfoEntry
+{
+ uint32 Displayid; // 0
+ // 1-3,unused
+ float scale; // 4
+ // 5-13,unused
+};
+
+struct CreatureFamilyEntry
+{
+ uint32 ID; // 0
+ float minScale; // 1
+ uint32 minScaleLevel; // 2 0/1
+ float maxScale; // 3
+ uint32 maxScaleLevel; // 4 0/60
+ uint32 skillLine; // 5
+ uint32 skillLine2; // 6
+ uint32 petFoodMask; // 7
+ char* Name[16]; // 8-23
+ // 24 string flags, unused
+ // 25 icon, unused
+};
+
+struct CreatureSpellDataEntry
+{
+ uint32 ID; // 0
+ //uint32 spellId[4]; // 1-4 hunter pet learned spell (for later use)
+};
+
+struct DurabilityCostsEntry
+{
+ uint32 Itemlvl; // 0
+ uint32 multiplier[29]; // 1-29
+};
+
+struct DurabilityQualityEntry
+{
+ uint32 Id; // 0
+ float quality_mod; // 1
+};
+
+struct EmotesTextEntry
+{
+ uint32 Id;
+ uint32 textid;
+};
+
+struct FactionEntry
+{
+ uint32 ID; // 0
+ int32 reputationListID; // 1
+ uint32 BaseRepRaceMask[4]; // 2-5 Base reputation race masks (see enum Races)
+ uint32 BaseRepClassMask[4]; // 6-9 Base reputation class masks (see enum Classes)
+ int32 BaseRepValue[4]; // 10-13 Base reputation values
+ uint32 ReputationFlags[4]; // 14-17 Default flags to apply
+ uint32 team; // 18 enum Team
+ char* name[16]; // 19-34
+ // 35 string flags, unused
+ //char* description[16]; // 36-51 unused
+ // 52 string flags, unused
+};
+
+enum FactionMasks
+{
+ FACTION_MASK_PLAYER = 1, // any player
+ FACTION_MASK_ALLIANCE = 2, // player or creature from alliance team
+ FACTION_MASK_HORDE = 4, // player or creature from horde team
+ FACTION_MASK_MONSTER = 8 // aggressive creature from monster team
+ // if none flags set then non-aggressive creature
+};
+
+struct FactionTemplateEntry
+{
+ uint32 ID; // 0
+ uint32 faction; // 1
+ uint32 factionFlags; // 2 specific flags for that faction
+ uint32 ourMask; // 3 if mask set (see FactionMasks) then faction included in masked team
+ uint32 friendlyMask; // 4 if mask set (see FactionMasks) then faction friendly to masked team
+ uint32 hostileMask; // 5 if mask set (see FactionMasks) then faction hostile to masked team
+ uint32 enemyFaction1; // 6
+ uint32 enemyFaction2; // 7
+ uint32 enemyFaction3; // 8
+ uint32 enemyFaction4; // 9
+ uint32 friendFaction1; // 10
+ uint32 friendFaction2; // 11
+ uint32 friendFaction3; // 12
+ uint32 friendFaction4; // 13
+ //------------------------------------------------------- end structure
+
+ // helpers
+ bool IsFriendlyTo(FactionTemplateEntry const& entry) const
+ {
+ if(enemyFaction1 == entry.faction || enemyFaction2 == entry.faction || enemyFaction3 == entry.faction || enemyFaction4 == entry.faction )
+ return false;
+ if(friendFaction1 == entry.faction || friendFaction2 == entry.faction || friendFaction3 == entry.faction || friendFaction4 == entry.faction )
+ return true;
+ return (friendlyMask & entry.ourMask) || (ourMask & entry.friendlyMask);
+ }
+ bool IsHostileTo(FactionTemplateEntry const& entry) const
+ {
+ if(enemyFaction1 == entry.faction || enemyFaction2 == entry.faction || enemyFaction3 == entry.faction || enemyFaction4 == entry.faction )
+ return true;
+ if(friendFaction1 == entry.faction || friendFaction2 == entry.faction || friendFaction3 == entry.faction || friendFaction4 == entry.faction )
+ return false;
+ return (hostileMask & entry.ourMask) != 0;
+ }
+ bool IsHostileToPlayers() const { return (hostileMask & FACTION_MASK_PLAYER) !=0; }
+ bool IsNeutralToAll() const { return hostileMask == 0 && friendlyMask == 0 && enemyFaction1==0 && enemyFaction2==0 && enemyFaction3==0 && enemyFaction4==0; }
+ bool IsContestedGuardFaction() const { return (factionFlags & FACTION_TEMPLATE_FLAG_CONTESTED_GUARD)!=0; }
+};
+
+struct GemPropertiesEntry
+{
+ uint32 ID;
+ uint32 spellitemenchantement;
+ uint32 color;
+};
+
+#define GT_MAX_LEVEL 100
+struct GtCombatRatingsEntry
+{
+ float ratio;
+};
+
+struct GtChanceToMeleeCritBaseEntry
+{
+ float base;
+};
+
+struct GtChanceToMeleeCritEntry
+{
+ float ratio;
+};
+
+struct GtChanceToSpellCritBaseEntry
+{
+ float base;
+};
+
+struct GtChanceToSpellCritEntry
+{
+ float ratio;
+};
+
+struct GtOCTRegenHPEntry
+{
+ float ratio;
+};
+
+//struct GtOCTRegenMPEntry
+//{
+// float ratio;
+//};
+
+struct GtRegenHPPerSptEntry
+{
+ float ratio;
+};
+
+struct GtRegenMPPerSptEntry
+{
+ float ratio;
+};
+
+struct ItemEntry
+{
+ uint32 ID;
+ uint32 DisplayId;
+ uint32 InventoryType;
+ uint32 Sheath;
+};
+
+struct ItemDisplayInfoEntry
+{
+ uint32 ID;
+ uint32 randomPropertyChance;
+};
+
+//struct ItemCondExtCostsEntry
+//{
+// uint32 ID;
+// uint32 condExtendedCost; // ItemPrototype::CondExtendedCost
+// uint32 itemextendedcostentry; // ItemPrototype::ExtendedCost
+// uint32 arenaseason; // arena season number(1-4)
+//};
+
+struct ItemExtendedCostEntry
+{
+ uint32 ID; // 0 extended-cost entry id
+ uint32 reqhonorpoints; // 1 required honor points
+ uint32 reqarenapoints; // 2 required arena points
+ uint32 reqitem[5]; // 3-7 required item id
+ uint32 reqitemcount[5]; // 8-12 required count of 1st item
+ uint32 reqpersonalarenarating; // 13 required personal arena rating
+};
+
+struct ItemRandomPropertiesEntry
+{
+ uint32 ID; // 0
+ //char* internalName // 1 unused
+ uint32 enchant_id[3]; // 2-4
+ // 5-6 unused, 0 only values, reserved for additional enchantments?
+ //char* nameSuffix[16] // 7-22, unused
+ // 23 nameSufix flags, unused
+};
+
+struct ItemRandomSuffixEntry
+{
+ uint32 ID; // 0
+ //char* name[16] // 1-16 unused
+ // 17, name flags, unused
+ // 18 unused
+ uint32 enchant_id[3]; // 19-21
+ uint32 prefix[3]; // 22-24
+};
+
+struct ItemSetEntry
+{
+ //uint32 id // 0 item set ID
+ char* name[16]; // 1-16
+ // 17 string flags, unused
+ // 18-28 items from set, but not have all items listed, use ItemPrototype::ItemSet instead
+ // 29-34 unused
+ uint32 spells[8]; // 35-42
+ uint32 items_to_triggerspell[8]; // 43-50
+ uint32 required_skill_id; // 51
+ uint32 required_skill_value; // 52
+};
+
+struct LockEntry
+{
+ uint32 ID; // 0
+ uint32 keytype[5]; // 1-5
+ // 6-8, not used
+ uint32 key[5]; // 9-13
+ // 14-16, not used
+ uint32 requiredminingskill; // 17
+ uint32 requiredlockskill; // 18
+ // 19-32, not used
+};
+
+struct MailTemplateEntry
+{
+ uint32 ID; // 0
+ //char* subject[16]; // 1-16
+ // 17 name flags, unused
+ //char* content[16]; // 18-33
+};
+
+enum MapTypes
+{
+ MAP_COMMON = 0,
+ MAP_INSTANCE = 1,
+ MAP_RAID = 2,
+ MAP_BATTLEGROUND = 3,
+ MAP_ARENA = 4
+};
+
+struct MapEntry
+{
+ uint32 MapID; // 0
+ //char* internalname; // 1 unused
+ uint32 map_type; // 2
+ // 3 unused
+ char* name[16]; // 4-19
+ // 20 name flags, unused
+ // 21-23 unused (something PvPZone related - levels?)
+ // 24-26
+ uint32 linked_zone; // 27 common zone for instance and continent map
+ //char* hordeIntro // 28-43 text for PvP Zones
+ // 44 intro text flags
+ //char* allianceIntro // 45-60 text for PvP Zones
+ // 46 intro text flags
+ // 47-61 not used
+ uint32 multimap_id; // 62
+ // 63-65 not used
+ //chat* unknownText1 // 66-81 unknown empty text fields, possible normal Intro text.
+ // 82 text flags
+ //chat* heroicIntroText // 83-98 heroic mode requirement text
+ // 99 text flags
+ //chat* unknownText2 // 100-115 unknown empty text fields
+ // 116 text flags
+ int32 parent_map; // 117 map_id of parent map
+ //float start_x // 118 enter x coordinate (if exist single entry)
+ //float start_y // 119 enter y coordinate (if exist single entry)
+ uint32 resetTimeRaid; // 120
+ uint32 resetTimeHeroic; // 121
+ // 122-123
+ uint32 addon; // 124 (0-original maps,1-tbc addon)
+
+ // Helpers
+ bool IsExpansionMap() const { return addon != 0; }
+ bool Instanceable() const { return map_type == MAP_INSTANCE || map_type == MAP_RAID; }
+ // NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable
+ bool IsDungeon() const { return map_type == MAP_INSTANCE || map_type == MAP_RAID; }
+ bool IsRaid() const { return map_type == MAP_RAID; }
+ bool IsBattleGround() const { return map_type == MAP_BATTLEGROUND; }
+ bool IsBattleArena() const { return map_type == MAP_ARENA; }
+ bool IsBattleGroundOrArena() const { return map_type == MAP_BATTLEGROUND || map_type == MAP_ARENA; }
+ bool SupportsHeroicMode() const { return resetTimeHeroic && !resetTimeRaid; }
+ bool HasResetTime() const { return resetTimeHeroic || resetTimeRaid; }
+
+ bool IsMountAllowed() const
+ {
+ return !IsDungeon() ||
+ MapID==568 || MapID==309 || MapID==209 || MapID==534 ||
+ MapID==560 || MapID==509 || MapID==269;
+ }
+};
+
+struct QuestSortEntry
+{
+ uint32 id; // 0, sort id
+ //char* name[16]; // 1-16, unused
+ // 17 name flags, unused
+};
+
+struct RandomPropertiesPointsEntry
+{
+ //uint32 Id; // 0 hidden key
+ uint32 itemLevel; // 1
+ uint32 EpicPropertiesPoints[5]; // 2-6
+ uint32 RarePropertiesPoints[5]; // 7-11
+ uint32 UncommonPropertiesPoints[5]; // 12-16
+};
+
+//struct SkillLineCategoryEntry{
+// uint32 id; // 0 hidden key
+// char* name[16]; // 1 - 17 Category name
+// // 18 string flag
+// uint32 displayOrder; // Display order in character tab
+//};
+
+//struct SkillRaceClassInfoEntry{
+// uint32 id; // 0
+// uint32 skillId; // 1 present some refrences to unknown skill
+// uint32 raceMask; // 2
+// uint32 classMask; // 3
+// uint32 flags; // 4 mask for some thing
+// uint32 reqLevel; // 5
+// uint32 skillTierId; // 6
+// uint32 skillCostID; // 7
+//};
+
+//struct SkillTiersEntry{
+// uint32 id; // 0
+// uint32 skillValue[16]; // 1-17 unknown possibly add value on learn?
+// uint32 maxSkillValue[16]; // Max value for rank
+//};
+
+struct SkillLineEntry
+{
+ uint32 id; // 0
+ uint32 categoryId; // 1 (index from SkillLineCategory.dbc)
+ //uint32 skillCostID; // 2 not used
+ char* name[16]; // 3-18
+ // 19 string flags, not used
+ //char* description[16]; // 20-35, not used
+ // 36 string flags, not used
+ uint32 spellIcon; // 37
+};
+
+enum AbilytyLearnType
+{
+ ABILITY_LEARNED_ON_GET_PROFESSION_SKILL = 1,
+ ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL = 2
+};
+
+struct SkillLineAbilityEntry
+{
+ uint32 id; // 0, INDEX
+ uint32 skillId; // 1
+ uint32 spellId; // 2
+ uint32 racemask; // 3
+ uint32 classmask; // 4
+ //uint32 racemaskNot; // 5 always 0 in 2.4.2
+ //uint32 classmaskNot; // 6 always 0 in 2.4.2
+ uint32 req_skill_value; // 7 for trade skill.not for training.
+ uint32 forward_spellid; // 8
+ uint32 learnOnGetSkill; // 9 can be 1 or 2 for spells learned on get skill
+ uint32 max_value; // 10
+ uint32 min_value; // 11
+ // 12-13, unknown, always 0
+ uint32 reqtrainpoints; // 14
+};
+
+struct SoundEntriesEntry
+{
+ uint32 Id; // 0, sound id
+ //uint32 Type; // 1, sound type (10 generally for creature, etc)
+ //char* InternalName; // 2, internal name, for use in lookup command for example
+ //char* FileName[10]; // 3-12, file names
+ //uint32 Unk13[10]; // 13-22, linked with file names?
+ //char* Path; // 23
+ // 24-28, unknown
+};
+
+struct SpellEntry
+{
+ uint32 Id; // 0 normally counted from 0 field (but some tools start counting from 1, check this before tool use for data view!)
+ uint32 Category; // 1
+ //uint32 castUI // 2 not used
+ uint32 Dispel; // 3
+ uint32 Mechanic; // 4
+ uint32 Attributes; // 5
+ uint32 AttributesEx; // 6
+ uint32 AttributesEx2; // 7
+ uint32 AttributesEx3; // 8
+ uint32 AttributesEx4; // 9
+ uint32 AttributesEx5; // 10
+ //uint32 AttributesEx6; // 11 not used
+ uint32 Stances; // 12
+ uint32 StancesNot; // 13
+ uint32 Targets; // 14
+ uint32 TargetCreatureType; // 15
+ uint32 RequiresSpellFocus; // 16
+ //uint32 FacingCasterFlags; // 17 not used
+ uint32 CasterAuraState; // 18
+ uint32 TargetAuraState; // 19
+ uint32 CasterAuraStateNot; // 20
+ uint32 TargetAuraStateNot; // 21
+ uint32 CastingTimeIndex; // 22
+ uint32 RecoveryTime; // 23
+ uint32 CategoryRecoveryTime; // 24
+ uint32 InterruptFlags; // 25
+ uint32 AuraInterruptFlags; // 26
+ uint32 ChannelInterruptFlags; // 27
+ uint32 procFlags; // 28
+ uint32 procChance; // 29
+ uint32 procCharges; // 30
+ uint32 maxLevel; // 31
+ uint32 baseLevel; // 32
+ uint32 spellLevel; // 33
+ uint32 DurationIndex; // 34
+ uint32 powerType; // 35
+ uint32 manaCost; // 36
+ uint32 manaCostPerlevel; // 37
+ uint32 manaPerSecond; // 38
+ uint32 manaPerSecondPerLevel; // 39
+ uint32 rangeIndex; // 40
+ float speed; // 41
+ //uint32 modalNextSpell; // 42
+ uint32 StackAmount; // 43
+ uint32 Totem[2]; // 44-45
+ int32 Reagent[8]; // 46-53
+ uint32 ReagentCount[8]; // 54-61
+ int32 EquippedItemClass; // 62 (value)
+ int32 EquippedItemSubClassMask; // 63 (mask)
+ int32 EquippedItemInventoryTypeMask; // 64 (mask)
+ uint32 Effect[3]; // 65-67
+ int32 EffectDieSides[3]; // 68-70
+ uint32 EffectBaseDice[3]; // 71-73
+ float EffectDicePerLevel[3]; // 74-76
+ float EffectRealPointsPerLevel[3]; // 77-79
+ int32 EffectBasePoints[3]; // 80-82 (don't must be used in spell/auras explicitly, must be used cached Spell::m_currentBasePoints)
+ uint32 EffectMechanic[3]; // 83-85
+ uint32 EffectImplicitTargetA[3]; // 86-88
+ uint32 EffectImplicitTargetB[3]; // 89-91
+ uint32 EffectRadiusIndex[3]; // 92-94 - spellradius.dbc
+ uint32 EffectApplyAuraName[3]; // 95-97
+ uint32 EffectAmplitude[3]; // 98-100
+ float EffectMultipleValue[3]; // 101-103
+ uint32 EffectChainTarget[3]; // 104-106
+ uint32 EffectItemType[3]; // 107-109
+ int32 EffectMiscValue[3]; // 110-112
+ int32 EffectMiscValueB[3]; // 113-115
+ uint32 EffectTriggerSpell[3]; // 116-118
+ float EffectPointsPerComboPoint[3]; // 119-121
+ uint32 SpellVisual; // 122
+ // 123 not used
+ uint32 SpellIconID; // 124
+ uint32 activeIconID; // 125
+ //uint32 spellPriority; // 126
+ char* SpellName[16]; // 127-142
+ //uint32 SpellNameFlag; // 143
+ char* Rank[16]; // 144-159
+ //uint32 RankFlags; // 160
+ //char* Description[16]; // 161-176 not used
+ //uint32 DescriptionFlags; // 177 not used
+ //char* ToolTip[16]; // 178-193 not used
+ //uint32 ToolTipFlags; // 194 not used
+ uint32 ManaCostPercentage; // 195
+ uint32 StartRecoveryCategory; // 196
+ uint32 StartRecoveryTime; // 197
+ uint32 MaxTargetLevel; // 198
+ uint32 SpellFamilyName; // 199
+ uint64 SpellFamilyFlags; // 200+201
+ uint32 MaxAffectedTargets; // 202
+ uint32 DmgClass; // 203 defenseType
+ uint32 PreventionType; // 204
+ //uint32 StanceBarOrder; // 205 not used
+ float DmgMultiplier[3]; // 206-208
+ //uint32 MinFactionId; // 209 not used, and 0 in 2.4.2
+ //uint32 MinReputation; // 210 not used, and 0 in 2.4.2
+ //uint32 RequiredAuraVision; // 211 not used
+ uint32 TotemCategory[2]; // 212-213
+ uint32 AreaId; // 214
+ uint32 SchoolMask; // 215 school mask
+
+ private:
+ // prevent creating custom entries (copy data from original in fact)
+ SpellEntry(SpellEntry const&); // DON'T must have implementation
+};
+
+typedef std::set<uint32> SpellCategorySet;
+typedef std::map<uint32,SpellCategorySet > SpellCategoryStore;
+typedef std::set<uint32> PetFamilySpellsSet;
+typedef std::map<uint32,PetFamilySpellsSet > PetFamilySpellsStore;
+
+struct SpellCastTimesEntry
+{
+ uint32 ID; // 0
+ int32 CastTime; // 1
+ //float CastTimePerLevel; // 2 unsure / per skill?
+ //int32 MinCastTime; // 3 unsure
+};
+
+struct SpellFocusObjectEntry
+{
+ uint32 ID; // 0
+ //char* Name[16]; // 1-15 unused
+ // 16 string flags, unused
+};
+
+// stored in SQL table
+struct SpellThreatEntry
+{
+ uint32 spellId;
+ int32 threat;
+};
+
+struct SpellRadiusEntry
+{
+ uint32 ID;
+ float Radius;
+ float Radius2;
+};
+
+struct SpellRangeEntry
+{
+ uint32 ID;
+ float minRange;
+ float maxRange;
+};
+
+struct SpellShapeshiftEntry
+{
+ uint32 ID; // 0
+ //uint32 buttonPosition; // 1 unused
+ //char* Name[16]; // 2-17 unused
+ //uint32 NameFlags; // 18 unused
+ uint32 flags1; // 19
+ int32 creatureType; // 20 <=0 humanoid, other normal creature types
+ //uint32 unk1; // 21 unused
+ uint32 attackSpeed; // 22
+ //uint32 modelID; // 23 unused, alliance modelid (where horde case?)
+ //uint32 unk2; // 24 unused
+ //uint32 unk3; // 25 unused
+ //uint32 unk4; // 26 unused
+ //uint32 unk5; // 27 unused
+ //uint32 unk6; // 28 unused
+ //uint32 unk7; // 29 unused
+ //uint32 unk8; // 30 unused
+ //uint32 unk9; // 31 unused
+ //uint32 unk10; // 32 unused
+ //uint32 unk11; // 33 unused
+ //uint32 unk12; // 34 unused
+};
+
+struct SpellDurationEntry
+{
+ uint32 ID;
+ int32 Duration[3];
+};
+
+enum ItemEnchantmentType
+{
+ ITEM_ENCHANTMENT_TYPE_NONE = 0,
+ ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL = 1,
+ ITEM_ENCHANTMENT_TYPE_DAMAGE = 2,
+ ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL = 3,
+ ITEM_ENCHANTMENT_TYPE_RESISTANCE = 4,
+ ITEM_ENCHANTMENT_TYPE_STAT = 5,
+ ITEM_ENCHANTMENT_TYPE_TOTEM = 6
+};
+
+struct SpellItemEnchantmentEntry
+{
+ uint32 ID; // 0
+ uint32 type[3]; // 1-3
+ uint32 amount[3]; // 4-6
+ //uint32 amount2[3] // 7-9 always same as similar `amount` value
+ uint32 spellid[3]; // 10-12
+ char* description[16]; // 13-29
+ // 30 description flags
+ uint32 aura_id; // 31
+ uint32 slot; // 32
+ uint32 GemID; // 33
+ uint32 EnchantmentCondition; // 34
+};
+
+struct SpellItemEnchantmentConditionEntry
+{
+ uint32 ID;
+ uint8 Color[5];
+ uint8 Comparator[5];
+ uint8 CompareColor[5];
+ uint32 Value[5];
+};
+
+struct StableSlotPricesEntry
+{
+ uint32 Slot;
+ uint32 Price;
+};
+
+struct TalentEntry
+{
+ uint32 TalentID; // 0
+ uint32 TalentTab; // 1 index in TalentTab.dbc (TalentTabEntry)
+ uint32 Row; // 2
+ uint32 Col; // 3
+ uint32 RankID[5]; // 4-8
+ // 9-12 not used, always 0, maybe not used high ranks
+ uint32 DependsOn; // 13 index in Talent.dbc (TalentEntry)
+ // 14-15 not used
+ uint32 DependsOnRank; // 16
+ // 17-19 not used
+ uint32 DependsOnSpell; // 20 req.spell
+};
+
+struct TalentTabEntry
+{
+ uint32 TalentTabID; // 0
+ //char* name[16]; // 1-16, unused
+ //uint32 nameFlags; // 17, unused
+ //unit32 spellicon; // 18
+ // 19 not used
+ uint32 ClassMask; // 20
+ uint32 tabpage; // 21
+ //char* internalname; // 22
+};
+
+struct TaxiPathEntry
+{
+ uint32 ID;
+ uint32 from;
+ uint32 to;
+ uint32 price;
+};
+
+struct TaxiNodesEntry
+{
+ uint32 ID; // 0
+ uint32 map_id; // 1
+ float x; // 2
+ float y; // 3
+ float z; // 4
+ //char* name[16]; // 5-21
+ // 22 string flags, unused
+ uint32 horde_mount_type; // 23
+ uint32 alliance_mount_type; // 24
+};
+
+enum TotemCategoryType
+{
+ TOTEM_CATEGORY_TYPE_KNIFE = 1,
+ TOTEM_CATEGORY_TYPE_TOTEM = 2,
+ TOTEM_CATEGORY_TYPE_ROD = 3,
+ TOTEM_CATEGORY_TYPE_PICK = 21,
+ TOTEM_CATEGORY_TYPE_STONE = 22,
+ TOTEM_CATEGORY_TYPE_HAMMER = 23,
+ TOTEM_CATEGORY_TYPE_SPANNER = 24
+};
+
+struct TotemCategoryEntry
+{
+ uint32 ID; // 0
+ //char* name[16]; // 1-16
+ // 17 string flags, unused
+ uint32 categoryType; // 18 (one for specialization)
+ uint32 categoryMask; // 19 (compatibility mask for same type: different for totems, compatible from high to low for rods)
+};
+
+struct WorldMapAreaEntry
+{
+ //uint32 ID; // 0
+ uint32 map_id; // 1
+ uint32 area_id; // 2 index (continent 0 areas ignored)
+ //char* internal_name // 3
+ float y1; // 4
+ float y2; // 5
+ float x1; // 6
+ float x2; // 7
+ int32 virtual_map_id; // 8 -1 (map_id have correct map) other: virtual map where zone show (map_id - where zone in fact internally)
+};
+
+struct WorldSafeLocsEntry
+{
+ uint32 ID; // 0
+ uint32 map_id; // 1
+ float x; // 2
+ float y; // 3
+ float z; // 4
+ //char* name[16] // 5-20 name, unused
+ // 21 name flags, unused
+};
+
+// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
+#if defined( __GNUC__ )
+#pragma pack()
+#else
+#pragma pack(pop)
+#endif
+
+// Structures not used for casting to loaded DBC data and not required then packing
+struct TalentSpellPos
+{
+ TalentSpellPos() : talent_id(0), rank(0) {}
+ TalentSpellPos(uint16 _talent_id, uint8 _rank) : talent_id(_talent_id), rank(_rank) {}
+
+ uint16 talent_id;
+ uint8 rank;
+};
+
+typedef std::map<uint32,TalentSpellPos> TalentSpellPosMap;
+
+struct TaxiPathBySourceAndDestination
+{
+ TaxiPathBySourceAndDestination() : ID(0),price(0) {}
+ TaxiPathBySourceAndDestination(uint32 _id,uint32 _price) : ID(_id),price(_price) {}
+
+ uint32 ID;
+ uint32 price;
+};
+typedef std::map<uint32,TaxiPathBySourceAndDestination> TaxiPathSetForSource;
+typedef std::map<uint32,TaxiPathSetForSource> TaxiPathSetBySource;
+
+struct TaxiPathNode
+{
+ TaxiPathNode() : mapid(0), x(0),y(0),z(0),actionFlag(0),delay(0) {}
+ TaxiPathNode(uint32 _mapid, float _x, float _y, float _z, uint32 _actionFlag, uint32 _delay) : mapid(_mapid), x(_x),y(_y),z(_z),actionFlag(_actionFlag),delay(_delay) {}
+
+ uint32 mapid;
+ float x;
+ float y;
+ float z;
+ uint32 actionFlag;
+ uint32 delay;
+};
+typedef std::vector<TaxiPathNode> TaxiPathNodeList;
+typedef std::vector<TaxiPathNodeList> TaxiPathNodesByPath;
+
+#define TaxiMaskSize 16
+typedef uint32 TaxiMask[TaxiMaskSize];
+#endif
diff --git a/src/shared/Database/DBCfmt.cpp b/src/shared/Database/DBCfmt.cpp
new file mode 100644
index 00000000000..651a0b12944
--- /dev/null
+++ b/src/shared/Database/DBCfmt.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+const char AreaTableEntryfmt[]="iiinixxxxxissssssssssssssssxixxxxxx";
+const char AreaTriggerEntryfmt[]="niffffffff";
+const char BankBagSlotPricesEntryfmt[]="ni";
+const char BattlemasterListEntryfmt[]="niiixxxxxiiiixxssssssssssssssssxx";
+const char CharTitlesEntryfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi";
+const char ChatChannelsEntryfmt[]="iixssssssssssssssssxxxxxxxxxxxxxxxxxx";
+ // ChatChannelsEntryfmt, index not used (more compact store)
+const char ChrClassesEntryfmt[]="nxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxix";
+const char ChrRacesEntryfmt[]="nxixiixxixxxxissssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+const char CreatureDisplayInfofmt[]="nxxxfxxxxxxxxx";
+const char CreatureFamilyfmt[]="nfifiiiissssssssssssssssxx";
+const char CreatureSpellDatafmt[]="nxxxxxxxx";
+const char DurabilityCostsfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiii";
+const char DurabilityQualityfmt[]="nf";
+const char EmoteEntryfmt[]="nxixxxxxxxxxxxxxxxx";
+const char FactionEntryfmt[]="niiiiiiiiiiiiiiiiiissssssssssssssssxxxxxxxxxxxxxxxxxx";
+const char FactionTemplateEntryfmt[]="niiiiiiiiiiiii";
+const char GemPropertiesEntryfmt[]="nixxi";
+const char GtCombatRatingsfmt[]="f";
+const char GtChanceToMeleeCritBasefmt[]="f";
+const char GtChanceToMeleeCritfmt[]="f";
+const char GtChanceToSpellCritBasefmt[]="f";
+const char GtChanceToSpellCritfmt[]="f";
+const char GtOCTRegenHPfmt[]="f";
+//const char GtOCTRegenMPfmt[]="f";
+const char GtRegenHPPerSptfmt[]="f";
+const char GtRegenMPPerSptfmt[]="f";
+const char Itemfmt[]="niii";
+//const char ItemDisplayTemplateEntryfmt[]="nxxxxxxxxxxixxxxxxxxxxx";
+//const char ItemCondExtCostsEntryfmt[]="xiii";
+const char ItemExtendedCostEntryfmt[]="niiiiiiiiiiiii";
+const char ItemRandomPropertiesfmt[]="nxiiixxxxxxxxxxxxxxxxxxx";
+const char ItemRandomSuffixfmt[]="nxxxxxxxxxxxxxxxxxxiiiiii";
+const char ItemSetEntryfmt[]="dssssssssssssssssxxxxxxxxxxxxxxxxxxiiiiiiiiiiiiiiiiii";
+const char LockEntryfmt[]="niiiiixxxiiiiixxxiixxxxxxxxxxxxxx";
+const char MailTemplateEntryfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+const char MapEntryfmt[]="nxixssssssssssssssssxxxxxxxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixxiixxi";
+const char QuestSortEntryfmt[]="nxxxxxxxxxxxxxxxxx";
+const char RandomPropertiesPointsfmt[]="niiiiiiiiiiiiiii";
+const char SkillLinefmt[]="nixssssssssssssssssxxxxxxxxxxxxxxxxxxi";
+const char SkillLineAbilityfmt[]="niiiixxiiiiixxi";
+const char SoundEntriesfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+const char SpellCastTimefmt[]="nixx";
+const char SpellDurationfmt[]="niii";
+const char SpellEntryfmt[]="nixiiiiiiiixiiiiixiiiiiiiiiiiiiiiiiiiiiiifxiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffffffiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiifffixiixssssssssssssssssxssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiiiiiiiiiixfffxxxiiii";
+const char SpellFocusObjectfmt[]="nxxxxxxxxxxxxxxxxx";
+const char SpellItemEnchantmentfmt[]="niiiiiixxxiiissssssssssssssssxiiii";
+const char SpellItemEnchantmentConditionfmt[]="nbbbbbxxxxxbbbbbbbbbbiiiiiXXXXX";
+const char SpellRadiusfmt[]="nfxf";
+const char SpellRangefmt[]="nffxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+const char SpellShapeshiftfmt[]="nxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxx";
+const char StableSlotPricesfmt[] = "ni";
+const char TalentEntryfmt[]="niiiiiiiixxxxixxixxxi";
+const char TalentTabEntryfmt[]="nxxxxxxxxxxxxxxxxxxxiix";
+const char TaxiNodesEntryfmt[]="nifffxxxxxxxxxxxxxxxxxii";
+const char TaxiPathEntryfmt[]="niii";
+const char TaxiPathNodeEntryfmt[]="diiifffiixx";
+const char TotemCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxii";
+const char WorldMapAreaEntryfmt[]="xinxffffi";
+const char WorldSafeLocsEntryfmt[]="nifffxxxxxxxxxxxxxxxxx";
diff --git a/src/shared/Database/Database.cpp b/src/shared/Database/Database.cpp
new file mode 100644
index 00000000000..5726aeaa340
--- /dev/null
+++ b/src/shared/Database/Database.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "DatabaseEnv.h"
+#include "Config/ConfigEnv.h"
+
+#include <ctime>
+#include <iostream>
+#include <fstream>
+
+Database::~Database()
+{
+ /*Delete objects*/
+}
+
+bool Database::Initialize(const char *)
+{
+ // Enable logging of SQL commands (usally only GM commands)
+ // (See method: PExecuteLog)
+ m_logSQL = sConfig.GetBoolDefault("LogSQL", false);
+ m_logsDir = sConfig.GetStringDefault("LogsDir","");
+ if(!m_logsDir.empty())
+ {
+ if((m_logsDir.at(m_logsDir.length()-1)!='/') && (m_logsDir.at(m_logsDir.length()-1)!='\\'))
+ m_logsDir.append("/");
+ }
+
+ return true;
+}
+
+void Database::ThreadStart()
+{
+}
+
+void Database::ThreadEnd()
+{
+}
+
+void Database::escape_string(std::string& str)
+{
+ if(str.empty())
+ return;
+
+ char* buf = new char[str.size()*2+1];
+ escape_string(buf,str.c_str(),str.size());
+ str = buf;
+ delete[] buf;
+}
+
+bool Database::PExecuteLog(const char * format,...)
+{
+ if (!format)
+ return false;
+
+ va_list ap;
+ char szQuery [MAX_QUERY_LEN];
+ va_start(ap, format);
+ int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
+ va_end(ap);
+
+ if(res==-1)
+ {
+ sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
+ return false;
+ }
+
+ if( m_logSQL )
+ {
+ time_t curr;
+ tm local;
+ time(&curr); // get current time_t value
+ local=*(localtime(&curr)); // dereference and assign
+ char fName[128];
+ sprintf( fName, "%04d-%02d-%02d_logSQL.sql", local.tm_year+1900, local.tm_mon+1, local.tm_mday );
+
+ FILE* log_file;
+ std::string logsDir_fname = m_logsDir+fName;
+ log_file = fopen(logsDir_fname.c_str(), "a");
+ if (log_file)
+ {
+ fprintf(log_file, "%s;\n", szQuery);
+ fclose(log_file);
+ }
+ else
+ {
+ // The file could not be opened
+ sLog.outError("SQL-Logging is disabled - Log file for the SQL commands could not be openend: %s",fName);
+ }
+ }
+
+ return Execute(szQuery);
+}
+
+void Database::SetResultQueue(SqlResultQueue * queue)
+{
+ m_queryQueues[ZThread::ThreadImpl::current()] = queue;
+}
+
+QueryResult* Database::PQuery(const char *format,...)
+{
+ if(!format) return NULL;
+
+ va_list ap;
+ char szQuery [MAX_QUERY_LEN];
+ va_start(ap, format);
+ int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
+ va_end(ap);
+
+ if(res==-1)
+ {
+ sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
+ return false;
+ }
+
+ return Query(szQuery);
+}
+
+bool Database::PExecute(const char * format,...)
+{
+ if (!format)
+ return false;
+
+ va_list ap;
+ char szQuery [MAX_QUERY_LEN];
+ va_start(ap, format);
+ int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
+ va_end(ap);
+
+ if(res==-1)
+ {
+ sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
+ return false;
+ }
+
+ return Execute(szQuery);
+}
+
+bool Database::DirectPExecute(const char * format,...)
+{
+ if (!format)
+ return false;
+
+ va_list ap;
+ char szQuery [MAX_QUERY_LEN];
+ va_start(ap, format);
+ int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
+ va_end(ap);
+
+ if(res==-1)
+ {
+ sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
+ return false;
+ }
+
+ return DirectExecute(szQuery);
+}
diff --git a/src/shared/Database/Database.h b/src/shared/Database/Database.h
new file mode 100644
index 00000000000..40097773430
--- /dev/null
+++ b/src/shared/Database/Database.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef DATABASE_H
+#define DATABASE_H
+
+#include "zthread/Thread.h"
+#include "../src/zthread/ThreadImpl.h"
+#include "Utilities/HashMap.h"
+#include "Database/SqlDelayThread.h"
+
+class SqlTransaction;
+class SqlResultQueue;
+class SqlQueryHolder;
+
+typedef HM_NAMESPACE::hash_map<ZThread::ThreadImpl*, SqlTransaction*> TransactionQueues;
+typedef HM_NAMESPACE::hash_map<ZThread::ThreadImpl*, SqlResultQueue*> QueryQueues;
+
+#define MAX_QUERY_LEN 1024
+
+class MANGOS_DLL_SPEC Database
+{
+ protected:
+ Database() : m_threadBody(NULL), m_delayThread(NULL) {};
+
+ TransactionQueues m_tranQueues; ///< Transaction queues from diff. threads
+ QueryQueues m_queryQueues; ///< Query queues from diff threads
+ SqlDelayThread* m_threadBody; ///< Pointer to delay sql executer
+ ZThread::Thread* m_delayThread; ///< Pointer to executer thread
+
+ public:
+
+ virtual ~Database();
+
+ virtual bool Initialize(const char *infoString);
+ virtual void InitDelayThread() = 0;
+ virtual void HaltDelayThread() = 0;
+
+ virtual QueryResult* Query(const char *sql) = 0;
+ QueryResult* PQuery(const char *format,...) ATTR_PRINTF(2,3);
+
+ /// Async queries and query holders, implemented in DatabaseImpl.h
+ template<class Class>
+ bool AsyncQuery(Class *object, void (Class::*method)(QueryResult*), const char *sql);
+ template<class Class, typename ParamType1>
+ bool AsyncQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char *sql);
+ template<typename ParamType1>
+ bool AsyncQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param1, const char *sql);
+ template<class Class>
+ bool AsyncPQuery(Class *object, void (Class::*method)(QueryResult*), const char *format,...) ATTR_PRINTF(4,5);
+ template<class Class, typename ParamType1>
+ bool AsyncPQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char *format,...) ATTR_PRINTF(5,6);
+ template<typename ParamType1>
+ bool AsyncPQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param1, const char *format,...) ATTR_PRINTF(5,6);
+ template<class Class>
+ bool DelayQueryHolder(Class *object, void (Class::*method)(QueryResult*, SqlQueryHolder*), SqlQueryHolder *holder);
+ template<class Class, typename ParamType1>
+ bool DelayQueryHolder(Class *object, void (Class::*method)(QueryResult*, SqlQueryHolder*, ParamType1), SqlQueryHolder *holder, ParamType1 param1);
+
+ virtual bool Execute(const char *sql) = 0;
+ bool PExecute(const char *format,...) ATTR_PRINTF(2,3);
+ virtual bool DirectExecute(const char* sql) = 0;
+ bool DirectPExecute(const char *format,...) ATTR_PRINTF(2,3);
+
+ // Writes SQL commands to a LOG file (see mangosd.conf "LogSQL")
+ bool PExecuteLog(const char *format,...) ATTR_PRINTF(2,3);
+
+ virtual bool BeginTransaction() // nothing do if DB not support transactions
+ {
+ return true;
+ }
+ virtual bool CommitTransaction() // nothing do if DB not support transactions
+ {
+ return true;
+ }
+ virtual bool RollbackTransaction() // can't rollback without transaction support
+ {
+ return false;
+ }
+
+ virtual operator bool () const = 0;
+
+ virtual unsigned long escape_string(char *to, const char *from, unsigned long length) { strncpy(to,from,length); return length; }
+ void escape_string(std::string& str);
+
+ // must be called before first query in thread (one time for thread using one from existed Database objects)
+ virtual void ThreadStart();
+ // must be called before finish thread run (one time for thread using one from existed Database objects)
+ virtual void ThreadEnd();
+
+ // sets the result queue of the current thread, be careful what thread you call this from
+ void SetResultQueue(SqlResultQueue * queue);
+
+ private:
+ bool m_logSQL;
+ std::string m_logsDir;
+};
+#endif
diff --git a/src/shared/Database/DatabaseEnv.h b/src/shared/Database/DatabaseEnv.h
new file mode 100644
index 00000000000..e393b4d6de5
--- /dev/null
+++ b/src/shared/Database/DatabaseEnv.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined(DATABASEENV_H)
+#define DATABASEENV_H
+
+#include "Common.h"
+#include "Log.h"
+#include "Errors.h"
+
+#include "Database/DBCStores.h"
+#include "Database/Field.h"
+#include "Database/QueryResult.h"
+
+#ifdef DO_POSTGRESQL
+#include "Database/QueryResultPostgre.h"
+#include "Database/Database.h"
+#include "Database/DatabasePostgre.h"
+typedef DatabasePostgre DatabaseType;
+#define _LIKE_ "ILIKE"
+#define _TABLE_SIM_ "\""
+#else
+#include "Database/QueryResultMysql.h"
+#include "Database/QueryResultSqlite.h"
+#include "Database/Database.h"
+#include "Database/DatabaseMysql.h"
+#include "Database/DatabaseSqlite.h"
+typedef DatabaseMysql DatabaseType;
+#define _LIKE_ "LIKE"
+#define _TABLE_SIM_ "`"
+#endif
+
+extern DatabaseType WorldDatabase;
+extern DatabaseType CharacterDatabase;
+extern DatabaseType loginDatabase;
+
+#endif
diff --git a/src/shared/Database/DatabaseImpl.h b/src/shared/Database/DatabaseImpl.h
new file mode 100644
index 00000000000..682f7b25ef7
--- /dev/null
+++ b/src/shared/Database/DatabaseImpl.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "Database/Database.h"
+#include "Database/SqlOperations.h"
+
+/// Function body definitions for the template function members of the Database class
+
+template<class Class>
+bool
+Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult*), const char *sql)
+{
+ if (!sql) return false;
+ ZThread::ThreadImpl * queryThread = ZThread::ThreadImpl::current();
+ QueryQueues::iterator itr = m_queryQueues.find(queryThread);
+ if (itr == m_queryQueues.end()) return false;
+ m_threadBody->Delay(new SqlQuery(sql, new MaNGOS::QueryCallback<Class>(object, method), itr->second));
+ return true;
+}
+
+template<class Class, typename ParamType1>
+bool
+Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char *sql)
+{
+ if (!sql) return false;
+ ZThread::ThreadImpl * queryThread = ZThread::ThreadImpl::current();
+ QueryQueues::iterator itr = m_queryQueues.find(queryThread);
+ if (itr == m_queryQueues.end()) return false;
+ m_threadBody->Delay(new SqlQuery(sql, new MaNGOS::QueryCallback<Class, ParamType1>(object, method, (QueryResult*)NULL, param1), itr->second));
+ return true;
+}
+
+template<typename ParamType1>
+bool
+Database::AsyncQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param1, const char *sql)
+{
+ if (!sql) return false;
+ ZThread::ThreadImpl * queryThread = ZThread::ThreadImpl::current();
+ QueryQueues::iterator itr = m_queryQueues.find(queryThread);
+ if (itr == m_queryQueues.end()) return false;
+ m_threadBody->Delay(new SqlQuery(sql, new MaNGOS::SQueryCallback<ParamType1>(method, (QueryResult*)NULL, param1), itr->second));
+ return true;
+}
+
+template<class Class>
+bool
+Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult*), const char *format,...)
+{
+ if(!format) return false;
+
+ va_list ap;
+ char szQuery [MAX_QUERY_LEN];
+ va_start(ap, format);
+ int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
+ va_end(ap);
+
+ if(res==-1)
+ {
+ sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
+ return false;
+ }
+
+ return AsyncQuery(object, method, szQuery);
+}
+
+template<class Class, typename ParamType1>
+bool
+Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char *format,...)
+{
+ if(!format) return false;
+
+ va_list ap;
+ char szQuery [MAX_QUERY_LEN];
+ va_start(ap, format);
+ int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
+ va_end(ap);
+
+ if(res==-1)
+ {
+ sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
+ return false;
+ }
+
+ return AsyncQuery(object, method, param1, szQuery);
+}
+
+template<typename ParamType1>
+bool
+Database::AsyncPQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param1, const char *format,...)
+{
+ if(!format) return false;
+
+ va_list ap;
+ char szQuery [MAX_QUERY_LEN];
+ va_start(ap, format);
+ int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
+ va_end(ap);
+
+ if(res==-1)
+ {
+ sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
+ return false;
+ }
+
+ return AsyncQuery(method, param1, szQuery);
+}
+
+
+template<class Class>
+bool
+Database::DelayQueryHolder(Class *object, void (Class::*method)(QueryResult*, SqlQueryHolder*), SqlQueryHolder *holder)
+{
+ if (!holder) return false;
+ ZThread::ThreadImpl * queryThread = ZThread::ThreadImpl::current();
+ QueryQueues::iterator itr = m_queryQueues.find(queryThread);
+ if (itr == m_queryQueues.end()) return false;
+ holder->Execute(new MaNGOS::QueryCallback<Class, SqlQueryHolder*>(object, method, (QueryResult*)NULL, holder), m_threadBody, itr->second);
+ return true;
+}
+
+template<class Class, typename ParamType1>
+bool
+Database::DelayQueryHolder(Class *object, void (Class::*method)(QueryResult*, SqlQueryHolder*, ParamType1), SqlQueryHolder *holder, ParamType1 param1)
+{
+ if (!holder) return false;
+ ZThread::ThreadImpl * queryThread = ZThread::ThreadImpl::current();
+ QueryQueues::iterator itr = m_queryQueues.find(queryThread);
+ if (itr == m_queryQueues.end()) return false;
+ holder->Execute(new MaNGOS::QueryCallback<Class, SqlQueryHolder*, ParamType1>(object, method, (QueryResult*)NULL, holder, param1), m_threadBody, itr->second);
+ return true;
+}
diff --git a/src/shared/Database/DatabaseMysql.cpp b/src/shared/Database/DatabaseMysql.cpp
new file mode 100644
index 00000000000..b736a60aa1b
--- /dev/null
+++ b/src/shared/Database/DatabaseMysql.cpp
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef DO_POSTGRESQL
+
+#include "Util.h"
+#include "Policies/SingletonImp.h"
+#include "Platform/Define.h"
+#include "../src/zthread/ThreadImpl.h"
+#include "DatabaseEnv.h"
+#include "Database/MySQLDelayThread.h"
+#include "Database/SqlOperations.h"
+#include "Timer.h"
+
+void DatabaseMysql::ThreadStart()
+{
+ mysql_thread_init();
+}
+
+void DatabaseMysql::ThreadEnd()
+{
+ mysql_thread_end();
+}
+
+size_t DatabaseMysql::db_count = 0;
+
+DatabaseMysql::DatabaseMysql() : Database(), mMysql(0)
+{
+ // before first connection
+ if( db_count++ == 0 )
+ {
+ // Mysql Library Init
+ mysql_library_init(-1, NULL, NULL);
+
+ if (!mysql_thread_safe())
+ {
+ sLog.outError("FATAL ERROR: Used MySQL library isn't thread-safe.");
+ exit(1);
+ }
+ }
+}
+
+DatabaseMysql::~DatabaseMysql()
+{
+ if (m_delayThread)
+ HaltDelayThread();
+
+ if (mMysql)
+ mysql_close(mMysql);
+
+ //Free Mysql library pointers for last ~DB
+ if(--db_count == 0)
+ mysql_library_end();
+}
+
+bool DatabaseMysql::Initialize(const char *infoString)
+{
+
+ if(!Database::Initialize(infoString))
+ return false;
+
+ tranThread = NULL;
+ MYSQL *mysqlInit;
+ mysqlInit = mysql_init(NULL);
+ if (!mysqlInit)
+ {
+ sLog.outError( "Could not initialize Mysql connection" );
+ return false;
+ }
+
+ InitDelayThread();
+
+ Tokens tokens = StrSplit(infoString, ";");
+
+ Tokens::iterator iter;
+
+ std::string host, port_or_socket, user, password, database;
+ int port;
+ char const* unix_socket;
+
+ iter = tokens.begin();
+
+ if(iter != tokens.end())
+ host = *iter++;
+ if(iter != tokens.end())
+ port_or_socket = *iter++;
+ if(iter != tokens.end())
+ user = *iter++;
+ if(iter != tokens.end())
+ password = *iter++;
+ if(iter != tokens.end())
+ database = *iter++;
+
+ mysql_options(mysqlInit,MYSQL_SET_CHARSET_NAME,"utf8");
+ #ifdef WIN32
+ if(host==".") // named pipe use option (Windows)
+ {
+ unsigned int opt = MYSQL_PROTOCOL_PIPE;
+ mysql_options(mysqlInit,MYSQL_OPT_PROTOCOL,(char const*)&opt);
+ port = 0;
+ unix_socket = 0;
+ }
+ else // generic case
+ {
+ port = atoi(port_or_socket.c_str());
+ unix_socket = 0;
+ }
+ #else
+ if(host==".") // socket use option (Unix/Linux)
+ {
+ unsigned int opt = MYSQL_PROTOCOL_SOCKET;
+ mysql_options(mysqlInit,MYSQL_OPT_PROTOCOL,(char const*)&opt);
+ host = "localhost";
+ port = 0;
+ unix_socket = port_or_socket.c_str();
+ }
+ else // generic case
+ {
+ port = atoi(port_or_socket.c_str());
+ unix_socket = 0;
+ }
+ #endif
+
+ mMysql = mysql_real_connect(mysqlInit, host.c_str(), user.c_str(),
+ password.c_str(), database.c_str(), port, unix_socket, 0);
+
+ if (mMysql)
+ {
+ sLog.outDetail( "Connected to MySQL database at %s",
+ host.c_str());
+ sLog.outString( "MySQL client library: %s", mysql_get_client_info());
+ sLog.outString( "MySQL server ver: %s ", mysql_get_server_info( mMysql));
+
+ /*----------SET AUTOCOMMIT ON---------*/
+ // It seems mysql 5.0.x have enabled this feature
+ // by default. In crash case you can lose data!!!
+ // So better to turn this off
+ // ---
+ // This is wrong since mangos use transactions,
+ // autocommit is turned of during it.
+ // Setting it to on makes atomic updates work
+ if (!mysql_autocommit(mMysql, 1))
+ sLog.outDetail("AUTOCOMMIT SUCCESSFULLY SET TO 1");
+ else
+ sLog.outDetail("AUTOCOMMIT NOT SET TO 1");
+ /*-------------------------------------*/
+
+ // set connection properties to UTF8 to properly handle locales for different
+ // server configs - core sends data in UTF8, so MySQL must expect UTF8 too
+ PExecute("SET NAMES `utf8`");
+ PExecute("SET CHARACTER SET `utf8`");
+
+ return true;
+ }
+ else
+ {
+ sLog.outError( "Could not connect to MySQL database at %s: %s\n",
+ host.c_str(),mysql_error(mysqlInit));
+ mysql_close(mysqlInit);
+ return false;
+ }
+}
+
+QueryResult* DatabaseMysql::Query(const char *sql)
+{
+ if (!mMysql)
+ return 0;
+
+ MYSQL_RES *result = 0;
+ uint64 rowCount = 0;
+ uint32 fieldCount = 0;
+
+ {
+ // guarded block for thread-safe mySQL request
+ ZThread::Guard<ZThread::FastMutex> query_connection_guard(mMutex);
+ #ifdef MANGOS_DEBUG
+ uint32 _s = getMSTime();
+ #endif
+ if(mysql_query(mMysql, sql))
+ {
+ sLog.outErrorDb( "SQL: %s", sql );
+ sLog.outErrorDb("query ERROR: %s", mysql_error(mMysql));
+ return NULL;
+ }
+ else
+ {
+ #ifdef MANGOS_DEBUG
+ sLog.outDebug("[%u ms] SQL: %s", getMSTimeDiff(_s,getMSTime()), sql );
+ #endif
+ }
+
+ result = mysql_store_result(mMysql);
+
+ rowCount = mysql_affected_rows(mMysql);
+ fieldCount = mysql_field_count(mMysql);
+ // end guarded block
+ }
+
+ if (!result )
+ return NULL;
+
+ if (!rowCount)
+ {
+ mysql_free_result(result);
+ return NULL;
+ }
+
+ QueryResultMysql *queryResult = new QueryResultMysql(result, rowCount, fieldCount);
+
+ queryResult->NextRow();
+
+ return queryResult;
+}
+
+bool DatabaseMysql::Execute(const char *sql)
+{
+ if (!mMysql)
+ return false;
+
+ // don't use queued execution if it has not been initialized
+ if (!m_threadBody) return DirectExecute(sql);
+
+ tranThread = ZThread::ThreadImpl::current(); // owner of this transaction
+ TransactionQueues::iterator i = m_tranQueues.find(tranThread);
+ if (i != m_tranQueues.end() && i->second != NULL)
+ { // Statement for transaction
+ i->second->DelayExecute(sql);
+ }
+ else
+ {
+ // Simple sql statement
+ m_threadBody->Delay(new SqlStatement(sql));
+ }
+
+ return true;
+}
+
+bool DatabaseMysql::DirectExecute(const char* sql)
+{
+ if (!mMysql)
+ return false;
+
+ {
+ // guarded block for thread-safe mySQL request
+ ZThread::Guard<ZThread::FastMutex> query_connection_guard(mMutex);
+ #ifdef MANGOS_DEBUG
+ uint32 _s = getMSTime();
+ #endif
+ if(mysql_query(mMysql, sql))
+ {
+ sLog.outErrorDb("SQL: %s", sql);
+ sLog.outErrorDb("SQL ERROR: %s", mysql_error(mMysql));
+ return false;
+ }
+ else
+ {
+ #ifdef MANGOS_DEBUG
+ sLog.outDebug("[%u ms] SQL: %s", getMSTimeDiff(_s,getMSTime()), sql );
+ #endif
+ }
+ // end guarded block
+ }
+
+ return true;
+}
+
+bool DatabaseMysql::_TransactionCmd(const char *sql)
+{
+ if (mysql_query(mMysql, sql))
+ {
+ sLog.outError("SQL: %s", sql);
+ sLog.outError("SQL ERROR: %s", mysql_error(mMysql));
+ return false;
+ }
+ else
+ {
+ DEBUG_LOG("SQL: %s", sql);
+ }
+ return true;
+}
+
+bool DatabaseMysql::BeginTransaction()
+{
+ if (!mMysql)
+ return false;
+
+ // don't use queued execution if it has not been initialized
+ if (!m_threadBody)
+ {
+ if (tranThread==ZThread::ThreadImpl::current())
+ return false; // huh? this thread already started transaction
+ mMutex.acquire();
+ if (!_TransactionCmd("START TRANSACTION"))
+ {
+ mMutex.release(); // can't start transaction
+ return false;
+ }
+ return true; // transaction started
+ }
+
+ tranThread = ZThread::ThreadImpl::current(); // owner of this transaction
+ TransactionQueues::iterator i = m_tranQueues.find(tranThread);
+ if (i != m_tranQueues.end() && i->second != NULL)
+ // If for thread exists queue and also contains transaction
+ // delete that transaction (not allow trans in trans)
+ delete i->second;
+
+ m_tranQueues[tranThread] = new SqlTransaction();
+
+ return true;
+}
+
+bool DatabaseMysql::CommitTransaction()
+{
+ if (!mMysql)
+ return false;
+
+ // don't use queued execution if it has not been initialized
+ if (!m_threadBody)
+ {
+ if (tranThread!=ZThread::ThreadImpl::current())
+ return false;
+ bool _res = _TransactionCmd("COMMIT");
+ tranThread = NULL;
+ mMutex.release();
+ return _res;
+ }
+
+ tranThread = ZThread::ThreadImpl::current();
+ TransactionQueues::iterator i = m_tranQueues.find(tranThread);
+ if (i != m_tranQueues.end() && i->second != NULL)
+ {
+ m_threadBody->Delay(i->second);
+ i->second = NULL;
+ return true;
+ }
+ else
+ return false;
+}
+
+bool DatabaseMysql::RollbackTransaction()
+{
+ if (!mMysql)
+ return false;
+
+ // don't use queued execution if it has not been initialized
+ if (!m_threadBody)
+ {
+ if (tranThread!=ZThread::ThreadImpl::current())
+ return false;
+ bool _res = _TransactionCmd("ROLLBACK");
+ tranThread = NULL;
+ mMutex.release();
+ return _res;
+ }
+
+ tranThread = ZThread::ThreadImpl::current();
+ TransactionQueues::iterator i = m_tranQueues.find(tranThread);
+ if (i != m_tranQueues.end() && i->second != NULL)
+ {
+ delete i->second;
+ i->second = NULL;
+ }
+ return true;
+}
+
+unsigned long DatabaseMysql::escape_string(char *to, const char *from, unsigned long length)
+{
+ if (!mMysql || !to || !from || !length)
+ return 0;
+
+ return(mysql_real_escape_string(mMysql, to, from, length));
+}
+
+void DatabaseMysql::InitDelayThread()
+{
+ assert(!m_delayThread);
+
+ //New delay thread for delay execute
+ m_delayThread = new ZThread::Thread(m_threadBody = new MySQLDelayThread(this));
+}
+
+void DatabaseMysql::HaltDelayThread()
+{
+ if (!m_threadBody || !m_delayThread) return;
+
+ m_threadBody->Stop(); //Stop event
+ m_delayThread->wait(); //Wait for flush to DB
+ delete m_delayThread; //This also deletes m_threadBody
+ m_delayThread = NULL;
+ m_threadBody = NULL;
+}
+#endif
diff --git a/src/shared/Database/DatabaseMysql.h b/src/shared/Database/DatabaseMysql.h
new file mode 100644
index 00000000000..2608212d52a
--- /dev/null
+++ b/src/shared/Database/DatabaseMysql.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef DO_POSTGRESQL
+
+#ifndef _DATABASEMYSQL_H
+#define _DATABASEMYSQL_H
+
+#include "Database.h"
+#include "Policies/Singleton.h"
+#include "zthread/FastMutex.h"
+
+#ifdef WIN32
+#define FD_SETSIZE 1024
+#include <winsock2.h>
+#include <mysql/mysql.h>
+#else
+#include <mysql.h>
+#endif
+
+class MANGOS_DLL_SPEC DatabaseMysql : public Database
+{
+ friend class MaNGOS::OperatorNew<DatabaseMysql>;
+
+ public:
+ DatabaseMysql();
+ ~DatabaseMysql();
+
+ //! Initializes Mysql and connects to a server.
+ /*! infoString should be formated like hostname;username;password;database. */
+ bool Initialize(const char *infoString);
+ void InitDelayThread();
+ void HaltDelayThread();
+ QueryResult* Query(const char *sql);
+ bool Execute(const char *sql);
+ bool DirectExecute(const char* sql);
+ bool BeginTransaction();
+ bool CommitTransaction();
+ bool RollbackTransaction();
+
+ operator bool () const { return mMysql != NULL; }
+
+ unsigned long escape_string(char *to, const char *from, unsigned long length);
+ using Database::escape_string;
+
+ // must be call before first query in thread
+ void ThreadStart();
+ // must be call before finish thread run
+ void ThreadEnd();
+ private:
+ ZThread::FastMutex mMutex;
+
+ ZThread::ThreadImpl* tranThread;
+
+ MYSQL *mMysql;
+
+ static size_t db_count;
+
+ bool _TransactionCmd(const char *sql);
+};
+#endif
+#endif
diff --git a/src/shared/Database/DatabasePostgre.cpp b/src/shared/Database/DatabasePostgre.cpp
new file mode 100644
index 00000000000..637c2ac9522
--- /dev/null
+++ b/src/shared/Database/DatabasePostgre.cpp
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef DO_POSTGRESQL
+
+#include "Util.h"
+#include "Policies/SingletonImp.h"
+#include "Platform/Define.h"
+#include "../src/zthread/ThreadImpl.h"
+#include "DatabaseEnv.h"
+#include "Database/PGSQLDelayThread.h"
+#include "Database/SqlOperations.h"
+#include "Timer.h"
+
+void DatabasePostgre::ThreadStart()
+{
+}
+
+void DatabasePostgre::ThreadEnd()
+{
+}
+
+size_t DatabasePostgre::db_count = 0;
+
+DatabasePostgre::DatabasePostgre() : Database(), mPGconn(NULL)
+{
+ // before first connection
+ if( db_count++ == 0 )
+ {
+
+ if (!PQisthreadsafe())
+ {
+ sLog.outError("FATAL ERROR: PostgreSQL libpq isn't thread-safe.");
+ exit(1);
+ }
+ }
+}
+
+DatabasePostgre::~DatabasePostgre()
+{
+
+ if (m_delayThread)
+ HaltDelayThread();
+
+ if( mPGconn )
+ {
+ PQfinish(mPGconn);
+ mPGconn = NULL;
+ }
+}
+
+bool DatabasePostgre::Initialize(const char *infoString)
+{
+ if(!Database::Initialize(infoString))
+ return false;
+
+ tranThread = NULL;
+
+ InitDelayThread();
+
+ Tokens tokens = StrSplit(infoString, ";");
+
+ Tokens::iterator iter;
+
+ std::string host, port_or_socket, user, password, database;
+
+ iter = tokens.begin();
+
+ if(iter != tokens.end())
+ host = *iter++;
+ if(iter != tokens.end())
+ port_or_socket = *iter++;
+ if(iter != tokens.end())
+ user = *iter++;
+ if(iter != tokens.end())
+ password = *iter++;
+ if(iter != tokens.end())
+ database = *iter++;
+
+ mPGconn = PQsetdbLogin(host.c_str(), port_or_socket.c_str(), NULL, NULL, database.c_str(), user.c_str(), password.c_str());
+
+ /* check to see that the backend connection was successfully made */
+ if (PQstatus(mPGconn) != CONNECTION_OK)
+ {
+ sLog.outError( "Could not connect to Postgre database at %s: %s",
+ host.c_str(), PQerrorMessage(mPGconn));
+ PQfinish(mPGconn);
+ return false;
+ }
+ else
+ {
+ sLog.outDetail( "Connected to Postgre database at %s",
+ host.c_str());
+ sLog.outString( "PostgreSQL server ver: %d",PQserverVersion(mPGconn));
+ return true;
+ }
+
+}
+
+QueryResult* DatabasePostgre::Query(const char *sql)
+{
+ if (!mPGconn)
+ return 0;
+
+ uint64 rowCount = 0;
+ uint32 fieldCount = 0;
+
+ // guarded block for thread-safe request
+ ZThread::Guard<ZThread::FastMutex> query_connection_guard(mMutex);
+ #ifdef MANGOS_DEBUG
+ uint32 _s = getMSTime();
+ #endif
+ // Send the query
+ PGresult * result = PQexec(mPGconn, sql);
+ if (!result )
+ {
+ return NULL;
+ }
+
+ if (PQresultStatus(result) != PGRES_TUPLES_OK)
+ {
+ sLog.outErrorDb( "SQL : %s", sql );
+ sLog.outErrorDb( "SQL %s", PQerrorMessage(mPGconn));
+ PQclear(result);
+ return NULL;
+ }
+ else
+ {
+ #ifdef MANGOS_DEBUG
+ sLog.outDebug("[%u ms] SQL: %s", getMSTime() - _s, sql );
+ #endif
+ }
+
+ rowCount = PQntuples(result);
+ fieldCount = PQnfields(result);
+ // end guarded block
+
+ if (!rowCount)
+ {
+ PQclear(result);
+ return NULL;
+ }
+
+ QueryResultPostgre * queryResult = new QueryResultPostgre(result, rowCount, fieldCount);
+ queryResult->NextRow();
+
+ return queryResult;
+}
+
+bool DatabasePostgre::Execute(const char *sql)
+{
+
+ if (!mPGconn)
+ return false;
+
+ // don't use queued execution if it has not been initialized
+ if (!m_threadBody) return DirectExecute(sql);
+
+ tranThread = ZThread::ThreadImpl::current(); // owner of this transaction
+ TransactionQueues::iterator i = m_tranQueues.find(tranThread);
+ if (i != m_tranQueues.end() && i->second != NULL)
+ { // Statement for transaction
+ i->second->DelayExecute(sql);
+ }
+ else
+ {
+ // Simple sql statement
+ m_threadBody->Delay(new SqlStatement(sql));
+ }
+
+ return true;
+}
+
+bool DatabasePostgre::DirectExecute(const char* sql)
+{
+ if (!mPGconn)
+ return false;
+ {
+ // guarded block for thread-safe request
+ ZThread::Guard<ZThread::FastMutex> query_connection_guard(mMutex);
+ #ifdef MANGOS_DEBUG
+ uint32 _s = getMSTime();
+ #endif
+ PGresult *res = PQexec(mPGconn, sql);
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ sLog.outErrorDb( "SQL: %s", sql );
+ sLog.outErrorDb( "SQL %s", PQerrorMessage(mPGconn) );
+ return false;
+ }
+ else
+ {
+ #ifdef MANGOS_DEBUG
+ sLog.outDebug("[%u ms] SQL: %s", getMSTime() - _s, sql );
+ #endif
+ }
+ PQclear(res);
+
+ // end guarded block
+ }
+ return true;
+}
+
+bool DatabasePostgre::_TransactionCmd(const char *sql)
+{
+ if (!mPGconn)
+ return false;
+
+ PGresult *res = PQexec(mPGconn, sql);
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ sLog.outError("SQL: %s", sql);
+ sLog.outError("SQL ERROR: %s", PQerrorMessage(mPGconn));
+ return false;
+ }
+ else
+ {
+ DEBUG_LOG("SQL: %s", sql);
+ }
+ return true;
+}
+
+bool DatabasePostgre::BeginTransaction()
+{
+ if (!mPGconn)
+ return false;
+ // don't use queued execution if it has not been initialized
+ if (!m_threadBody)
+ {
+ if (tranThread==ZThread::ThreadImpl::current())
+ return false; // huh? this thread already started transaction
+ mMutex.acquire();
+ if (!_TransactionCmd("START TRANSACTION"))
+ {
+ mMutex.release(); // can't start transaction
+ return false;
+ }
+ return true;
+ }
+ // transaction started
+ tranThread = ZThread::ThreadImpl::current(); // owner of this transaction
+ TransactionQueues::iterator i = m_tranQueues.find(tranThread);
+ if (i != m_tranQueues.end() && i->second != NULL)
+ // If for thread exists queue and also contains transaction
+ // delete that transaction (not allow trans in trans)
+ delete i->second;
+
+ m_tranQueues[tranThread] = new SqlTransaction();
+
+ return true;
+}
+
+bool DatabasePostgre::CommitTransaction()
+{
+ if (!mPGconn)
+ return false;
+
+ // don't use queued execution if it has not been initialized
+ if (!m_threadBody)
+ {
+ if (tranThread!=ZThread::ThreadImpl::current())
+ return false;
+ bool _res = _TransactionCmd("COMMIT");
+ tranThread = NULL;
+ mMutex.release();
+ return _res;
+ }
+ tranThread = ZThread::ThreadImpl::current();
+ TransactionQueues::iterator i = m_tranQueues.find(tranThread);
+ if (i != m_tranQueues.end() && i->second != NULL)
+ {
+ m_threadBody->Delay(i->second);
+ i->second = NULL;
+ return true;
+ }
+ else
+ return false;
+}
+
+bool DatabasePostgre::RollbackTransaction()
+{
+ if (!mPGconn)
+ return false;
+ // don't use queued execution if it has not been initialized
+ if (!m_threadBody)
+ {
+ if (tranThread!=ZThread::ThreadImpl::current())
+ return false;
+ bool _res = _TransactionCmd("ROLLBACK");
+ tranThread = NULL;
+ mMutex.release();
+ return _res;
+ }
+ tranThread = ZThread::ThreadImpl::current();
+ TransactionQueues::iterator i = m_tranQueues.find(tranThread);
+ if (i != m_tranQueues.end() && i->second != NULL)
+ {
+ delete i->second;
+ i->second = NULL;
+ }
+ return true;
+}
+
+unsigned long DatabasePostgre::escape_string(char *to, const char *from, unsigned long length)
+{
+ if (!mPGconn || !to || !from || !length)
+ return 0;
+
+ return PQescapeString(to, from, length);
+}
+
+void DatabasePostgre::InitDelayThread()
+{
+ assert(!m_delayThread);
+
+ //New delay thread for delay execute
+ m_delayThread = new ZThread::Thread(m_threadBody = new PGSQLDelayThread(this));
+}
+
+void DatabasePostgre::HaltDelayThread()
+{
+ if (!m_threadBody || !m_delayThread) return;
+
+ m_threadBody->Stop(); //Stop event
+ m_delayThread->wait(); //Wait for flush to DB
+ delete m_delayThread; //This also deletes m_threadBody
+ m_delayThread = NULL;
+ m_threadBody = NULL;
+}
+#endif
diff --git a/src/shared/Database/DatabasePostgre.h b/src/shared/Database/DatabasePostgre.h
new file mode 100644
index 00000000000..b1929c46360
--- /dev/null
+++ b/src/shared/Database/DatabasePostgre.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _DatabasePostgre_H
+#define _DatabasePostgre_H
+
+#include "Policies/Singleton.h"
+#include "zthread/FastMutex.h"
+#include <stdarg.h>
+
+#ifdef WIN32
+#define FD_SETSIZE 1024
+#include <winsock2.h>
+#include <postgre/libpq-fe.h>
+#else
+#include <libpq-fe.h>
+#endif
+
+class DatabasePostgre : public Database
+{
+ friend class MaNGOS::OperatorNew<DatabasePostgre>;
+
+ public:
+ DatabasePostgre();
+ ~DatabasePostgre();
+
+ //! Initializes Postgres and connects to a server.
+ /*! infoString should be formated like hostname;username;password;database. */
+ bool Initialize(const char *infoString);
+ void InitDelayThread();
+ void HaltDelayThread();
+ QueryResult* Query(const char *sql);
+ bool Execute(const char *sql);
+ bool DirectExecute(const char* sql);
+ bool BeginTransaction();
+ bool CommitTransaction();
+ bool RollbackTransaction();
+
+ operator bool () const { return mPGconn != NULL; }
+
+ unsigned long escape_string(char *to, const char *from, unsigned long length);
+ using Database::escape_string;
+
+ // must be call before first query in thread
+ void ThreadStart();
+ // must be call before finish thread run
+ void ThreadEnd();
+ private:
+ ZThread::FastMutex mMutex;
+ ZThread::FastMutex tranMutex;
+
+ ZThread::ThreadImpl* tranThread;
+
+ PGconn *mPGconn;
+
+ static size_t db_count;
+
+ bool _TransactionCmd(const char *sql);
+};
+#endif
diff --git a/src/shared/Database/DatabaseSqlite.cpp b/src/shared/Database/DatabaseSqlite.cpp
new file mode 100644
index 00000000000..75307f9d430
--- /dev/null
+++ b/src/shared/Database/DatabaseSqlite.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef DO_POSTGRESQL
+
+#include "DatabaseEnv.h"
+
+DatabaseSqlite::DatabaseSqlite() : Database(), mSqlite(0)
+{
+}
+
+DatabaseSqlite::~DatabaseSqlite()
+{
+ if (mSqlite)
+ sqlite_close(mSqlite);
+}
+
+bool DatabaseSqlite::Initialize(const char *infoString)
+{
+ if(!Database::Initialize(infoString))
+ return false;
+
+ char *errmsg;
+
+ mSqlite = sqlite_open(infoString, 0, &errmsg);
+
+ if (!mSqlite)
+ {
+
+ if (errmsg)
+ sqlite_freemem(errmsg);
+ return false;
+ }
+
+ return true;
+}
+
+QueryResult* DatabaseSqlite::Query(const char *sql)
+{
+ char *errmsg;
+
+ if (!mSqlite)
+ return 0;
+
+ char **tableData;
+ int rowCount;
+ int fieldCount;
+
+ sqlite_get_table(mSqlite, sql, &tableData, &rowCount, &fieldCount, &errmsg);
+
+ if (!rowCount)
+ return 0;
+
+ if (!tableData)
+ {
+
+ if (errmsg)
+ sqlite_freemem(errmsg);
+ return 0;
+ }
+
+ QueryResultSqlite *queryResult = new QueryResultSqlite(tableData, rowCount, fieldCount);
+ if(!queryResult)
+ {
+
+ return 0;
+ }
+
+ queryResult->NextRow();
+
+ return queryResult;
+}
+
+bool DatabaseSqlite::Execute(const char *sql)
+{
+ char *errmsg;
+
+ if (!mSqlite)
+ return false;
+
+ if(sqlite_exec(mSqlite, sql, NULL, NULL, &errmsg) != SQLITE_OK)
+ return false;
+
+ return true;
+}
+#endif
diff --git a/src/shared/Database/DatabaseSqlite.h b/src/shared/Database/DatabaseSqlite.h
new file mode 100644
index 00000000000..37190a6b562
--- /dev/null
+++ b/src/shared/Database/DatabaseSqlite.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef DO_POSTGRESQL
+
+#ifndef _DATABASESQLITE_H
+#define _DATABASESQLITE_H
+
+#include <sqlite/sqlite.h>
+
+class DatabaseSqlite : public Database
+{
+ public:
+ DatabaseSqlite();
+ ~DatabaseSqlite();
+
+ bool Initialize(const char *infoString);
+
+ QueryResult* Query(const char *sql);
+ bool Execute(const char *sql);
+
+ operator bool () const { return mSqlite != NULL; }
+
+ private:
+ sqlite *mSqlite;
+};
+#endif
+#endif
diff --git a/src/shared/Database/Field.cpp b/src/shared/Database/Field.cpp
new file mode 100644
index 00000000000..5c693403c06
--- /dev/null
+++ b/src/shared/Database/Field.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "DatabaseEnv.h"
+
+Field::Field() :
+mValue(NULL), mType(DB_TYPE_UNKNOWN)
+{
+}
+
+Field::Field(Field &f)
+{
+ const char *value;
+
+ value = f.GetString();
+
+ if (value && (mValue = new char[strlen(value) + 1]))
+ strcpy(mValue, value);
+ else
+ mValue = NULL;
+
+ mType = f.GetType();
+}
+
+Field::Field(const char *value, enum Field::DataTypes type) :
+mType(type)
+{
+ if (value && (mValue = new char[strlen(value) + 1]))
+ strcpy(mValue, value);
+ else
+ mValue = NULL;
+}
+
+Field::~Field()
+{
+ if(mValue) delete [] mValue;
+}
+
+void Field::SetValue(const char *value)
+{
+ if(mValue) delete [] mValue;
+
+ if (value)
+ {
+ mValue = new char[strlen(value) + 1];
+ strcpy(mValue, value);
+ }
+ else
+ mValue = NULL;
+}
diff --git a/src/shared/Database/Field.h b/src/shared/Database/Field.h
new file mode 100644
index 00000000000..f829ec18424
--- /dev/null
+++ b/src/shared/Database/Field.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined(FIELD_H)
+#define FIELD_H
+
+class Field
+{
+ public:
+
+ enum DataTypes
+ {
+ DB_TYPE_UNKNOWN = 0x00,
+ DB_TYPE_STRING = 0x01,
+ DB_TYPE_INTEGER = 0x02,
+ DB_TYPE_FLOAT = 0x03,
+ DB_TYPE_BOOL = 0x04
+ };
+
+ Field();
+ Field(Field &f);
+ Field(const char *value, enum DataTypes type);
+
+ ~Field();
+
+ enum DataTypes GetType() const { return mType; }
+
+ const char *GetString() const { return mValue; }
+ std::string GetCppString() const
+ {
+ return mValue ? mValue : ""; // std::string s = 0 have undefine result in C++
+ }
+ float GetFloat() const { return mValue ? static_cast<float>(atof(mValue)) : 0.0f; }
+ bool GetBool() const { return mValue ? atoi(mValue) > 0 : false; }
+ int32 GetInt32() const { return mValue ? static_cast<int32>(atol(mValue)) : int32(0); }
+ uint8 GetUInt8() const { return mValue ? static_cast<uint8>(atol(mValue)) : uint8(0); }
+ uint16 GetUInt16() const { return mValue ? static_cast<uint16>(atol(mValue)) : uint16(0); }
+ int16 GetInt16() const { return mValue ? static_cast<int16>(atol(mValue)) : int16(0); }
+ uint32 GetUInt32() const { return mValue ? static_cast<uint32>(atol(mValue)) : uint32(0); }
+ uint64 GetUInt64() const
+ {
+ if(mValue)
+ {
+ uint64 value;
+ sscanf(mValue,I64FMTD,&value);
+ return value;
+ }
+ else
+ return 0;
+ }
+
+ void SetType(enum DataTypes type) { mType = type; }
+
+ void SetValue(const char *value);
+
+ private:
+ char *mValue;
+ enum DataTypes mType;
+};
+#endif
diff --git a/src/shared/Database/Makefile.am b/src/shared/Database/Makefile.am
new file mode 100644
index 00000000000..2d3a9fb5d5c
--- /dev/null
+++ b/src/shared/Database/Makefile.am
@@ -0,0 +1,62 @@
+# Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+## Process this file with automake to produce Makefile.in
+
+## Sub-directories to parse
+
+## CPP flags for includes, defines, etc.
+AM_CPPFLAGS = $(MYSQL_INCLUDES) $(POSTGRE_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(srcdir)/../../../dep/include -I$(srcdir)/../../framework -I$(srcdir)/../../shared -I$(srcdir)/../../../dep/include/g3dlite
+
+## Build MaNGOS shared library and its parts as convenience library.
+# All libraries will be convenience libraries. Might be changed to shared
+# later.
+noinst_LIBRARIES = libmangosdatabase.a
+
+libmangosdatabase_a_SOURCES = \
+ DBCStores.cpp \
+ DBCStores.h \
+ DBCStructure.h \
+ DBCfmt.cpp \
+ Database.cpp \
+ Database.h \
+ DatabaseEnv.h \
+ DatabaseImpl.h \
+ DatabaseMysql.cpp \
+ DatabasePostgre.cpp \
+ DatabaseMysql.h \
+ DatabasePostgre.h \
+ DatabaseSqlite.cpp \
+ DatabaseSqlite.h \
+ Field.cpp \
+ Field.h \
+ MySQLDelayThread.h \
+ PGSQLDelayThread.h \
+ QueryResult.h \
+ QueryResultMysql.cpp \
+ QueryResultMysql.h \
+ QueryResultPostgre.cpp \
+ QueryResultPostgre.h \
+ QueryResultSqlite.cpp \
+ QueryResultSqlite.h \
+ SQLStorage.cpp \
+ SQLStorage.h \
+ SqlDelayThread.cpp \
+ SqlDelayThread.h \
+ SqlOperations.cpp \
+ SqlOperations.h \
+ dbcfile.cpp \
+ dbcfile.h
diff --git a/src/shared/Database/MySQLDelayThread.h b/src/shared/Database/MySQLDelayThread.h
new file mode 100644
index 00000000000..dcc979d6d53
--- /dev/null
+++ b/src/shared/Database/MySQLDelayThread.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __MYSQLDELAYTHREAD_H
+#define __MYSQLDELAYTHREAD_H
+
+#include "Database/SqlDelayThread.h"
+
+class MySQLDelayThread : public SqlDelayThread
+{
+ public:
+ MySQLDelayThread(Database* db) : SqlDelayThread(db) {}
+ void Stop() { SqlDelayThread::Stop(); }
+};
+#endif //__MYSQLDELAYTHREAD_H
diff --git a/src/shared/Database/PGSQLDelayThread.h b/src/shared/Database/PGSQLDelayThread.h
new file mode 100644
index 00000000000..03907026899
--- /dev/null
+++ b/src/shared/Database/PGSQLDelayThread.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __PGSQLDELAYTHREAD_H
+#define __PGSQLDELAYTHREAD_H
+
+#include "Database/SqlDelayThread.h"
+
+class PGSQLDelayThread : public SqlDelayThread
+{
+ public:
+ PGSQLDelayThread(Database* db) : SqlDelayThread(db) {}
+ void Stop() { SqlDelayThread::Stop(); }
+};
+#endif //__PGSQLDELAYTHREAD_H
diff --git a/src/shared/Database/QueryResult.h b/src/shared/Database/QueryResult.h
new file mode 100644
index 00000000000..50ee98a9a22
--- /dev/null
+++ b/src/shared/Database/QueryResult.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined(QUERYRESULT_H)
+#define QUERYRESULT_H
+
+class MANGOS_DLL_SPEC QueryResult
+{
+ public:
+ QueryResult(uint64 rowCount, uint32 fieldCount)
+ : mFieldCount(fieldCount), mRowCount(rowCount) {}
+
+ virtual ~QueryResult() {}
+
+ virtual bool NextRow() = 0;
+
+ typedef std::map<uint32, std::string> FieldNames;
+
+ uint32 GetField_idx(const std::string &name) const
+ {
+ for(FieldNames::const_iterator iter = GetFiedNames().begin(); iter != GetFiedNames().end(); ++iter)
+ {
+ if(iter->second == name)
+ return iter->first;
+ }
+ assert(false && "unknown field name");
+ return uint32(-1);
+ }
+
+ Field *Fetch() const { return mCurrentRow; }
+
+ const Field & operator [] (int index) const { return mCurrentRow[index]; }
+
+ const Field & operator [] (const std::string &name) const
+ {
+ return mCurrentRow[GetField_idx(name)];
+ }
+
+ uint32 GetFieldCount() const { return mFieldCount; }
+ uint64 GetRowCount() const { return mRowCount; }
+ FieldNames const& GetFiedNames() const {return mFieldNames; }
+
+ protected:
+ Field *mCurrentRow;
+ uint32 mFieldCount;
+ uint64 mRowCount;
+ FieldNames mFieldNames;
+};
+#endif
diff --git a/src/shared/Database/QueryResultMysql.cpp b/src/shared/Database/QueryResultMysql.cpp
new file mode 100644
index 00000000000..b24e51c2352
--- /dev/null
+++ b/src/shared/Database/QueryResultMysql.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef DO_POSTGRESQL
+
+#include "DatabaseEnv.h"
+
+QueryResultMysql::QueryResultMysql(MYSQL_RES *result, uint64 rowCount, uint32 fieldCount) :
+QueryResult(rowCount, fieldCount), mResult(result)
+{
+
+ mCurrentRow = new Field[mFieldCount];
+ ASSERT(mCurrentRow);
+
+ MYSQL_FIELD *fields = mysql_fetch_fields(mResult);
+
+ for (uint32 i = 0; i < mFieldCount; i++)
+ {
+ mFieldNames[i] = fields[i].name;
+ mCurrentRow[i].SetType(ConvertNativeType(fields[i].type));
+ }
+}
+
+QueryResultMysql::~QueryResultMysql()
+{
+ EndQuery();
+}
+
+bool QueryResultMysql::NextRow()
+{
+ MYSQL_ROW row;
+
+ if (!mResult)
+ return false;
+
+ row = mysql_fetch_row(mResult);
+ if (!row)
+ {
+ EndQuery();
+ return false;
+ }
+
+ for (uint32 i = 0; i < mFieldCount; i++)
+ mCurrentRow[i].SetValue(row[i]);
+
+ return true;
+}
+
+void QueryResultMysql::EndQuery()
+{
+ if (mCurrentRow)
+ {
+ delete [] mCurrentRow;
+ mCurrentRow = 0;
+ }
+
+ if (mResult)
+ {
+ mysql_free_result(mResult);
+ mResult = 0;
+ }
+}
+
+enum Field::DataTypes QueryResultMysql::ConvertNativeType(enum_field_types mysqlType) const
+{
+ switch (mysqlType)
+ {
+ case FIELD_TYPE_TIMESTAMP:
+ case FIELD_TYPE_DATE:
+ case FIELD_TYPE_TIME:
+ case FIELD_TYPE_DATETIME:
+ case FIELD_TYPE_YEAR:
+ case FIELD_TYPE_STRING:
+ case FIELD_TYPE_VAR_STRING:
+ case FIELD_TYPE_BLOB:
+ case FIELD_TYPE_SET:
+ case FIELD_TYPE_NULL:
+ return Field::DB_TYPE_STRING;
+ case FIELD_TYPE_TINY:
+
+ case FIELD_TYPE_SHORT:
+ case FIELD_TYPE_LONG:
+ case FIELD_TYPE_INT24:
+ case FIELD_TYPE_LONGLONG:
+ case FIELD_TYPE_ENUM:
+ return Field::DB_TYPE_INTEGER;
+ case FIELD_TYPE_DECIMAL:
+ case FIELD_TYPE_FLOAT:
+ case FIELD_TYPE_DOUBLE:
+ return Field::DB_TYPE_FLOAT;
+ default:
+ return Field::DB_TYPE_UNKNOWN;
+ }
+}
+#endif
diff --git a/src/shared/Database/QueryResultMysql.h b/src/shared/Database/QueryResultMysql.h
new file mode 100644
index 00000000000..e62a1a4c120
--- /dev/null
+++ b/src/shared/Database/QueryResultMysql.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef DO_POSTGRESQL
+
+#if !defined(QUERYRESULTMYSQL_H)
+#define QUERYRESULTMYSQL_H
+
+#ifdef WIN32
+#define FD_SETSIZE 1024
+#include <winsock2.h>
+#include <mysql/mysql.h>
+#else
+#include <mysql.h>
+#endif
+
+class QueryResultMysql : public QueryResult
+{
+ public:
+ QueryResultMysql(MYSQL_RES *result, uint64 rowCount, uint32 fieldCount);
+
+ ~QueryResultMysql();
+
+ bool NextRow();
+
+ private:
+ enum Field::DataTypes ConvertNativeType(enum_field_types mysqlType) const;
+ void EndQuery();
+
+ MYSQL_RES *mResult;
+};
+#endif
+#endif
diff --git a/src/shared/Database/QueryResultPostgre.cpp b/src/shared/Database/QueryResultPostgre.cpp
new file mode 100644
index 00000000000..2cb6447b170
--- /dev/null
+++ b/src/shared/Database/QueryResultPostgre.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef DO_POSTGRESQL
+
+#include "DatabaseEnv.h"
+
+QueryResultPostgre::QueryResultPostgre(PGresult *result, uint64 rowCount, uint32 fieldCount) :
+QueryResult(rowCount, fieldCount), mResult(result), mTableIndex(0)
+{
+
+ mCurrentRow = new Field[mFieldCount];
+ ASSERT(mCurrentRow);
+
+ for (uint32 i = 0; i < mFieldCount; i++)
+ {
+ mFieldNames[i] = PQfname(result, i);
+ mCurrentRow[i].SetType(ConvertNativeType(PQftype( result, i )));
+ }
+}
+
+QueryResultPostgre::~QueryResultPostgre()
+{
+ EndQuery();
+}
+
+bool QueryResultPostgre::NextRow()
+{
+ if (!mResult)
+ return false;
+
+ if (mTableIndex >= mRowCount)
+ {
+ EndQuery();
+ return false;
+ }
+
+ char* pPQgetvalue;
+ for (int j = 0; j < mFieldCount; j++)
+ {
+ pPQgetvalue = PQgetvalue(mResult, mTableIndex, j);
+ if(pPQgetvalue && !(*pPQgetvalue))
+ pPQgetvalue = NULL;
+
+ mCurrentRow[j].SetValue(pPQgetvalue);
+ }
+ ++mTableIndex;
+
+ return true;
+}
+
+void QueryResultPostgre::EndQuery()
+{
+ if (mCurrentRow)
+ {
+ delete [] mCurrentRow;
+ mCurrentRow = 0;
+ }
+
+ if (mResult)
+ {
+ PQclear(mResult);
+ mResult = 0;
+ }
+}
+
+// see types in #include <postgre/pg_type.h>
+enum Field::DataTypes QueryResultPostgre::ConvertNativeType(Oid pOid ) const
+{
+ switch (pOid)
+ {
+ case BPCHAROID:
+ case CIDOID:
+ case CIDROID:
+ case CIRCLEOID:
+ case INETOID:
+ case NAMEOID:
+ case TEXTOID:
+ case VARCHAROID:
+ return Field::DB_TYPE_STRING;
+ case CASHOID:
+ case FLOAT4OID:
+ case FLOAT8OID:
+ case NUMERICOID:
+ return Field::DB_TYPE_FLOAT;
+ case DATEOID: // Date
+ case RELTIMEOID: // Date
+ case TIMEOID: // Time
+ case TIMETZOID: // Time
+ case ABSTIMEOID: // DateTime
+ case INTERVALOID: // DateTime
+ case TIMESTAMPOID: // DateTime
+ case TIMESTAMPTZOID: // DateTime
+ case INT2OID: // Int
+ case INT2VECTOROID: // Int
+ case INT4OID: // Int
+ case OIDOID: // Int
+ case CHAROID: // UInt
+ case INT8OID: // LongLong
+ return Field::DB_TYPE_INTEGER;
+ case BOOLOID:
+ return Field::DB_TYPE_BOOL; // Bool
+/*
+ case BOXOID: Rect;
+ case LINEOID: Rect;
+ case VARBITOID: BitArray;
+ case BYTEAOID: ByteArray;
+*/
+ case LSEGOID:
+ case OIDVECTOROID:
+ case PATHOID:
+ case POINTOID:
+ case POLYGONOID:
+ case REGPROCOID:
+ case TIDOID:
+ case TINTERVALOID:
+ case UNKNOWNOID:
+ case XIDOID:
+ default:
+ return Field::DB_TYPE_UNKNOWN;
+ }
+ return Field::DB_TYPE_UNKNOWN;
+}
+#endif
diff --git a/src/shared/Database/QueryResultPostgre.h b/src/shared/Database/QueryResultPostgre.h
new file mode 100644
index 00000000000..f6726d20123
--- /dev/null
+++ b/src/shared/Database/QueryResultPostgre.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined(QUERYRESULTPOSTGRE_H)
+#define QUERYRESULTPOSTGRE_H
+
+#ifdef WIN32
+#define FD_SETSIZE 1024
+#include <winsock2.h>
+#include <postgre/libpq-fe.h>
+#include <postgre/pg_type.h>
+#else
+#include <libpq-fe.h>
+//#include <pg_type.h>
+#endif
+
+class QueryResultPostgre : public QueryResult
+{
+ public:
+ QueryResultPostgre(PGresult *result, uint64 rowCount, uint32 fieldCount);
+
+ ~QueryResultPostgre();
+
+ bool NextRow();
+
+ private:
+ enum Field::DataTypes ConvertNativeType(Oid pOid) const;
+ void EndQuery();
+
+ PGresult *mResult;
+ uint32 mTableIndex;
+};
+#endif
diff --git a/src/shared/Database/QueryResultSqlite.cpp b/src/shared/Database/QueryResultSqlite.cpp
new file mode 100644
index 00000000000..3eca2f08d46
--- /dev/null
+++ b/src/shared/Database/QueryResultSqlite.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef DO_POSTGRESQL
+
+#include "DatabaseEnv.h"
+
+QueryResultSqlite::QueryResultSqlite(char **tableData, uint32 rowCount, uint32 fieldCount) :
+QueryResult(rowCount, fieldCount), mTableData(tableData), mTableIndex(0)
+{
+ mCurrentRow = new Field[mFieldCount];
+
+ for (uint32 i = 0; i < mFieldCount; i++)
+ {
+ mFieldNames[i] = mTableData[i];
+ mCurrentRow[i].SetType(Field::DB_TYPE_UNKNOWN);
+ }
+}
+
+QueryResultSqlite::~QueryResultSqlite()
+{
+ EndQuery();
+}
+
+bool QueryResultSqlite::NextRow()
+{
+ int startIndex;
+ uint32 i;
+
+ if (!mTableData)
+ return false;
+
+ if (mTableIndex >= mRowCount)
+ {
+ EndQuery();
+ return false;
+ }
+
+ startIndex = (mTableIndex + 1) * mFieldCount;
+ for (i = 0; i < mFieldCount; i++)
+ {
+ mCurrentRow[i].SetValue(mTableData[startIndex + i]);
+ }
+
+ ++mTableIndex;
+ return true;
+}
+
+void QueryResultSqlite::EndQuery()
+{
+ if (mCurrentRow)
+ {
+ delete [] mCurrentRow;
+ mCurrentRow = NULL;
+ }
+ if (mTableData)
+ {
+ sqlite_free_table(mTableData);
+ mTableData = NULL;
+ }
+}
+
+enum Field::DataTypes QueryResultSqlite::ConvertNativeType(const char* sqliteType) const
+{
+ if (sqliteType)
+ {
+ switch (*sqliteType)
+ {
+ case 'S':
+ return Field::DB_TYPE_STRING;
+ case 'I':
+ return Field::DB_TYPE_INTEGER;
+ case 'F':
+ return Field::DB_TYPE_FLOAT;
+ default:
+ return Field::DB_TYPE_UNKNOWN;
+ };
+ }
+ return Field::DB_TYPE_UNKNOWN;
+}
+#endif
diff --git a/src/shared/Database/QueryResultSqlite.h b/src/shared/Database/QueryResultSqlite.h
new file mode 100644
index 00000000000..c72e5727999
--- /dev/null
+++ b/src/shared/Database/QueryResultSqlite.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef DO_POSTGRESQL
+
+#if !defined(QUERYRESULTSQLITE_H)
+#define QUERYRESULTSQLITE_H
+
+#include <sqlite/sqlite.h>
+
+class QueryResultSqlite : public QueryResult
+{
+ public:
+ QueryResultSqlite(char **tableData, uint32 rowCount, uint32 fieldCount);
+
+ ~QueryResultSqlite();
+
+ bool NextRow();
+
+ private:
+ enum Field::DataTypes ConvertNativeType(const char* sqliteType) const;
+ void EndQuery();
+
+ char **mTableData;
+ uint32 mTableIndex;
+};
+#endif
+#endif
diff --git a/src/shared/Database/SQLStorage.cpp b/src/shared/Database/SQLStorage.cpp
new file mode 100644
index 00000000000..6041eaf282e
--- /dev/null
+++ b/src/shared/Database/SQLStorage.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "SQLStorage.h"
+#include "ProgressBar.h"
+#include "Log.h"
+#include "dbcfile.h"
+
+#ifdef DO_POSTGRESQL
+extern DatabasePostgre WorldDatabase;
+#else
+extern DatabaseMysql WorldDatabase;
+#endif
+
+const char CreatureInfofmt[]="iiiiiisssiiiiiiiiiiffiffiiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiilliiis";
+const char CreatureDataAddonInfofmt[]="iiiiiiis";
+const char CreatureModelfmt[]="iffbi";
+const char CreatureInfoAddonInfofmt[]="iiiiiiis";
+const char EquipmentInfofmt[]="iiiiiiiiii";
+const char GameObjectInfofmt[]="iiissiifiiiiiiiiiiiiiiiiiiiiiiiis";
+const char ItemPrototypefmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiffiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifsiiiii";
+const char PageTextfmt[]="isi";
+const char SpellThreatfmt[]="ii";
+const char InstanceTemplatefmt[]="iiiiiiffffs";
+
+SQLStorage sCreatureStorage(CreatureInfofmt,"entry","creature_template");
+SQLStorage sCreatureDataAddonStorage(CreatureDataAddonInfofmt,"guid","creature_addon");
+SQLStorage sCreatureModelStorage(CreatureModelfmt,"modelid","creature_model_info");
+SQLStorage sCreatureInfoAddonStorage(CreatureInfoAddonInfofmt,"entry","creature_template_addon");
+SQLStorage sEquipmentStorage(EquipmentInfofmt,"entry","creature_equip_template");
+SQLStorage sGOStorage(GameObjectInfofmt,"entry","gameobject_template");
+SQLStorage sItemStorage(ItemPrototypefmt,"entry","item_template");
+SQLStorage sPageTextStore(PageTextfmt,"entry","page_text");
+SQLStorage sSpellThreatStore(SpellThreatfmt,"entry","spell_threat");
+SQLStorage sInstanceTemplate(InstanceTemplatefmt,"map","instance_template");
+
+void SQLStorage::Free ()
+{
+ uint32 offset=0;
+ for(uint32 x=0;x<iNumFields;x++)
+ if (format[x]==FT_STRING)
+ {
+ for(uint32 y=0;y<MaxEntry;y++)
+ if(pIndex[y])
+ delete [] *(char**)((char*)(pIndex[y])+offset);
+
+ offset+=sizeof(char*);
+ }
+ else if (format[x]==FT_LOGIC)
+ offset+=sizeof(bool);
+ else if (format[x]==FT_BYTE)
+ offset+=sizeof(char);
+ else
+ offset+=4;
+
+ delete [] pIndex;
+ delete [] data;
+}
+
+void SQLStorage::Load ()
+{
+ uint32 maxi;
+ Field *fields;
+ QueryResult *result = WorldDatabase.PQuery("SELECT MAX(%s) FROM %s",entry_field,table);
+ if(!result)
+ {
+ sLog.outError("Error loading %s table (not exist?)\n",table);
+ exit(1); // Stop server at loading non exited table or not accessable table
+ }
+
+ maxi= (*result)[0].GetUInt32()+1;
+ delete result;
+
+ result = WorldDatabase.PQuery("SELECT COUNT(*) FROM %s",table);
+ if(result)
+ {
+ fields = result->Fetch();
+ RecordCount=fields[0].GetUInt32();
+ delete result;
+ }
+ else
+ RecordCount = 0;
+
+ result = WorldDatabase.PQuery("SELECT * FROM %s",table);
+
+ if(!result)
+ {
+ sLog.outError("%s table is empty!\n",table);
+ RecordCount = 0;
+ return;
+ }
+
+ uint32 recordsize=0;
+ uint32 offset=0;
+
+ if(iNumFields!=result->GetFieldCount())
+ {
+ RecordCount = 0;
+ sLog.outError("Error in %s table, probably sql file format was updated (there should be %d fields in sql).\n",table,iNumFields);
+ delete result;
+ exit(1); // Stop server at loading broken or non-compatiable table.
+ }
+
+ //get struct size
+ uint32 sc=0;
+ uint32 bo=0;
+ uint32 bb=0;
+ for(uint32 x=0;x<iNumFields;x++)
+ if(format[x]==FT_STRING)
+ ++sc;
+ else if (format[x]==FT_LOGIC)
+ ++bo;
+ else if (format[x]==FT_BYTE)
+ ++bb;
+ recordsize=(iNumFields-sc-bo-bb)*4+sc*sizeof(char*)+bo*sizeof(bool)+bb*sizeof(char);
+
+ char** newIndex=new char*[maxi];
+ memset(newIndex,0,maxi*sizeof(char*));
+
+ char * _data= new char[RecordCount *recordsize];
+ uint32 count=0;
+ barGoLink bar( RecordCount );
+ do
+ {
+ fields = result->Fetch();
+ bar.step();
+ char *p=(char*)&_data[recordsize*count];
+ newIndex[fields[0].GetUInt32()]=p;
+
+ offset=0;
+ for(uint32 x=0;x<iNumFields;x++)
+ switch(format[x])
+ {
+ case FT_LOGIC:
+ *((bool*)(&p[offset]))=(fields[x].GetUInt32()>0);
+ offset+=sizeof(bool);
+ break;
+ case FT_BYTE:
+ *((char*)(&p[offset]))=(fields[x].GetUInt8());
+ offset+=sizeof(char);
+ break;
+ case FT_INT:
+ *((uint32*)(&p[offset]))=fields[x].GetUInt32();
+ offset+=sizeof(uint32);
+ break;
+ case FT_FLOAT:
+ *((float*)(&p[offset]))=fields[x].GetFloat();
+ offset+=sizeof(float);
+ break;
+ case FT_STRING:
+ char const* tmp = fields[x].GetString();
+ char* st;
+ if(!tmp)
+ {
+ st=new char[1];
+ *st=0;
+ }
+ else
+ {
+ uint32 l=strlen(tmp)+1;
+ st=new char[l];
+ memcpy(st,tmp,l);
+ }
+ *((char**)(&p[offset]))=st;
+ offset+=sizeof(char*);
+ break;
+ }
+ ++count;
+ }while( result->NextRow() );
+
+ delete result;
+
+ pIndex =newIndex;
+ MaxEntry=maxi;
+ data=_data;
+}
diff --git a/src/shared/Database/SQLStorage.h b/src/shared/Database/SQLStorage.h
new file mode 100644
index 00000000000..4ddd44f593e
--- /dev/null
+++ b/src/shared/Database/SQLStorage.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef SQLSTORAGE_H
+#define SQLSTORAGE_H
+
+#include "Common.h"
+#include "Database/DatabaseEnv.h"
+
+class SQLStorage
+{
+ public:
+
+ SQLStorage(const char*fmt,const char * _entry_field,const char * sqlname)
+ {
+ format=fmt;
+ entry_field = _entry_field;
+ table=sqlname;
+ data=NULL;
+ pIndex=NULL;
+ iNumFields =strlen(fmt);
+ MaxEntry = 0;
+ }
+ ~SQLStorage()
+ {
+ Free();
+ }
+
+ template<class T>
+ T const* LookupEntry(uint32 id) const
+ {
+ if( id == 0 )
+ return NULL;
+ if(id >= MaxEntry)
+ return NULL;
+ return reinterpret_cast<T const*>(pIndex[id]);
+ }
+
+ uint32 RecordCount;
+ uint32 MaxEntry;
+ uint32 iNumFields;
+ void Load();
+ void Free();
+ private:
+ char** pIndex;
+
+ char *data;
+ const char *format;
+ const char *table;
+ const char *entry_field;
+ //bool HasString;
+};
+#endif
diff --git a/src/shared/Database/SqlDelayThread.cpp b/src/shared/Database/SqlDelayThread.cpp
new file mode 100644
index 00000000000..257a3d686e8
--- /dev/null
+++ b/src/shared/Database/SqlDelayThread.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "Database/SqlDelayThread.h"
+#include "Database/SqlOperations.h"
+#include "DatabaseEnv.h"
+
+SqlDelayThread::SqlDelayThread(Database* db) : m_dbEngine(db), m_running(true)
+{
+}
+
+void SqlDelayThread::run()
+{
+ SqlOperation* s;
+ #ifndef DO_POSTGRESQL
+ mysql_thread_init();
+ #endif
+
+ while (m_running)
+ {
+ // if the running state gets turned off while sleeping
+ // empty the queue before exiting
+ ZThread::Thread::sleep(10);
+ while (!m_sqlQueue.empty())
+ {
+ s = m_sqlQueue.next();
+ s->Execute(m_dbEngine);
+ delete s;
+ }
+ }
+
+ #ifndef DO_POSTGRESQL
+ mysql_thread_end();
+ #endif
+}
+
+void SqlDelayThread::Stop()
+{
+ m_running = false;
+}
diff --git a/src/shared/Database/SqlDelayThread.h b/src/shared/Database/SqlDelayThread.h
new file mode 100644
index 00000000000..dd729660dba
--- /dev/null
+++ b/src/shared/Database/SqlDelayThread.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __SQLDELAYTHREAD_H
+#define __SQLDELAYTHREAD_H
+
+#include "zthread/Thread.h"
+#include "zthread/Runnable.h"
+#include "zthread/FastMutex.h"
+#include "zthread/LockedQueue.h"
+
+class Database;
+class SqlOperation;
+
+class SqlDelayThread : public ZThread::Runnable
+{
+ typedef ZThread::LockedQueue<SqlOperation*, ZThread::FastMutex> SqlQueue;
+ private:
+ SqlQueue m_sqlQueue; ///< Queue of SQL statements
+ Database* m_dbEngine; ///< Pointer to used Database engine
+ bool m_running;
+
+ SqlDelayThread();
+ public:
+ SqlDelayThread(Database* db);
+
+ ///< Put sql statement to delay queue
+ inline void Delay(SqlOperation* sql) { m_sqlQueue.add(sql); }
+
+ virtual void Stop(); ///< Stop event
+ virtual void run(); ///< Main Thread loop
+};
+#endif //__SQLDELAYTHREAD_H
diff --git a/src/shared/Database/SqlOperations.cpp b/src/shared/Database/SqlOperations.cpp
new file mode 100644
index 00000000000..38febadbc5c
--- /dev/null
+++ b/src/shared/Database/SqlOperations.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "SqlOperations.h"
+#include "SqlDelayThread.h"
+#include "DatabaseEnv.h"
+#include "DatabaseImpl.h"
+
+/// ---- ASYNC STATEMENTS / TRANSACTIONS ----
+
+void SqlStatement::Execute(Database *db)
+{
+ /// just do it
+ db->DirectExecute(m_sql);
+}
+
+void SqlTransaction::Execute(Database *db)
+{
+ if(m_queue.empty())
+ return;
+ db->DirectExecute("START TRANSACTION");
+ while(!m_queue.empty())
+ {
+ char const *sql = m_queue.front();
+ m_queue.pop();
+
+ if(!db->DirectExecute(sql))
+ {
+ free((void*)const_cast<char*>(sql));
+ db->DirectExecute("ROLLBACK");
+ while(!m_queue.empty())
+ {
+ free((void*)const_cast<char*>(m_queue.front()));
+ m_queue.pop();
+ }
+ return;
+ }
+
+ free((void*)const_cast<char*>(sql));
+ }
+ db->DirectExecute("COMMIT");
+}
+
+/// ---- ASYNC QUERIES ----
+
+void SqlQuery::Execute(Database *db)
+{
+ if(!m_callback || !m_queue)
+ return;
+ /// execute the query and store the result in the callback
+ m_callback->SetResult(db->Query(m_sql));
+ /// add the callback to the sql result queue of the thread it originated from
+ m_queue->add(m_callback);
+}
+
+void SqlResultQueue::Update()
+{
+ /// execute the callbacks waiting in the synchronization queue
+ while(!empty())
+ {
+ MaNGOS::IQueryCallback * callback = next();
+ callback->Execute();
+ delete callback;
+ }
+}
+
+void SqlQueryHolder::Execute(MaNGOS::IQueryCallback * callback, SqlDelayThread *thread, SqlResultQueue *queue)
+{
+ if(!callback || !thread || !queue)
+ return;
+
+ /// delay the execution of the queries, sync them with the delay thread
+ /// which will in turn resync on execution (via the queue) and call back
+ SqlQueryHolderEx *holderEx = new SqlQueryHolderEx(this, callback, queue);
+ thread->Delay(holderEx);
+}
+
+bool SqlQueryHolder::SetQuery(size_t index, const char *sql)
+{
+ if(m_queries.size() <= index)
+ {
+ sLog.outError("Query index (%u) out of range (size: %u) for query: %s",index,m_queries.size(),sql);
+ return false;
+ }
+
+ if(m_queries[index].first != NULL)
+ {
+ sLog.outError("Attempt assign query to holder index (%u) where other query stored (Old: [%s] New: [%s])",index,m_queries.size(),m_queries[index].first,sql);
+ return false;
+ }
+
+ /// not executed yet, just stored (it's not called a holder for nothing)
+ m_queries[index] = SqlResultPair(strdup(sql), NULL);
+ return true;
+}
+
+bool SqlQueryHolder::SetPQuery(size_t index, const char *format, ...)
+{
+ if(!format)
+ {
+ sLog.outError("Query (index: %u) is empty.",index);
+ return false;
+ }
+
+ va_list ap;
+ char szQuery [MAX_QUERY_LEN];
+ va_start(ap, format);
+ int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
+ va_end(ap);
+
+ if(res==-1)
+ {
+ sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
+ return false;
+ }
+
+ return SetQuery(index,szQuery);
+}
+
+QueryResult* SqlQueryHolder::GetResult(size_t index)
+{
+ if(index < m_queries.size())
+ {
+ /// the query strings are freed on the first GetResult or in the destructor
+ if(m_queries[index].first != NULL)
+ {
+ free((void*)(const_cast<char*>(m_queries[index].first)));
+ m_queries[index].first = NULL;
+ }
+ /// when you get a result aways remember to delete it!
+ return m_queries[index].second;
+ }
+ else
+ return NULL;
+}
+
+void SqlQueryHolder::SetResult(size_t index, QueryResult *result)
+{
+ /// store the result in the holder
+ if(index < m_queries.size())
+ m_queries[index].second = result;
+}
+
+SqlQueryHolder::~SqlQueryHolder()
+{
+ for(size_t i = 0; i < m_queries.size(); i++)
+ {
+ /// if the result was never used, free the resources
+ /// results used already (getresult called) are expected to be deleted
+ if(m_queries[i].first != NULL)
+ {
+ free((void*)(const_cast<char*>(m_queries[i].first)));
+ if(m_queries[i].second)
+ delete m_queries[i].second;
+ }
+ }
+}
+
+void SqlQueryHolder::SetSize(size_t size)
+{
+ /// to optimize push_back, reserve the number of queries about to be executed
+ m_queries.resize(size);
+}
+
+void SqlQueryHolderEx::Execute(Database *db)
+{
+ if(!m_holder || !m_callback || !m_queue)
+ return;
+
+ /// we can do this, we are friends
+ std::vector<SqlQueryHolder::SqlResultPair> &queries = m_holder->m_queries;
+
+ for(size_t i = 0; i < queries.size(); i++)
+ {
+ /// execute all queries in the holder and pass the results
+ char const *sql = queries[i].first;
+ if(sql) m_holder->SetResult(i, db->Query(sql));
+ }
+
+ /// sync with the caller thread
+ m_queue->add(m_callback);
+}
diff --git a/src/shared/Database/SqlOperations.h b/src/shared/Database/SqlOperations.h
new file mode 100644
index 00000000000..0018a7ed08e
--- /dev/null
+++ b/src/shared/Database/SqlOperations.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __SQLOPERATIONS_H
+#define __SQLOPERATIONS_H
+
+#include "Common.h"
+
+#include "zthread/LockedQueue.h"
+#include "zthread/FastMutex.h"
+#include "zthread/Thread.h"
+#include <queue>
+#include "Utilities/Callback.h"
+
+/// ---- BASE ---
+
+class Database;
+class SqlDelayThread;
+
+class SqlOperation
+{
+ public:
+ virtual void OnRemove() { delete this; }
+ virtual void Execute(Database *db) = 0;
+ virtual ~SqlOperation() {}
+};
+
+/// ---- ASYNC STATEMENTS / TRANSACTIONS ----
+
+class SqlStatement : public SqlOperation
+{
+ private:
+ const char *m_sql;
+ public:
+ SqlStatement(const char *sql) : m_sql(strdup(sql)){}
+ ~SqlStatement() { void* tofree = const_cast<char*>(m_sql); free(tofree); }
+ void Execute(Database *db);
+};
+
+class SqlTransaction : public SqlOperation
+{
+ private:
+ std::queue<const char *> m_queue;
+ public:
+ SqlTransaction() {}
+ void DelayExecute(const char *sql) { m_queue.push(strdup(sql)); }
+ void Execute(Database *db);
+};
+
+/// ---- ASYNC QUERIES ----
+
+class SqlQuery; /// contains a single async query
+class QueryResult; /// the result of one
+class SqlResultQueue; /// queue for thread sync
+class SqlQueryHolder; /// groups several async quries
+class SqlQueryHolderEx; /// points to a holder, added to the delay thread
+
+class SqlResultQueue : public ZThread::LockedQueue<MaNGOS::IQueryCallback*, ZThread::FastMutex>
+{
+ public:
+ SqlResultQueue() {}
+ void Update();
+};
+
+class SqlQuery : public SqlOperation
+{
+ private:
+ const char *m_sql;
+ MaNGOS::IQueryCallback * m_callback;
+ SqlResultQueue * m_queue;
+ public:
+ SqlQuery(const char *sql, MaNGOS::IQueryCallback * callback, SqlResultQueue * queue)
+ : m_sql(strdup(sql)), m_callback(callback), m_queue(queue) {}
+ ~SqlQuery() { void* tofree = const_cast<char*>(m_sql); free(tofree); }
+ void Execute(Database *db);
+};
+
+class SqlQueryHolder
+{
+ friend class SqlQueryHolderEx;
+ private:
+ typedef std::pair<const char*, QueryResult*> SqlResultPair;
+ std::vector<SqlResultPair> m_queries;
+ public:
+ SqlQueryHolder() {}
+ ~SqlQueryHolder();
+ bool SetQuery(size_t index, const char *sql);
+ bool SetPQuery(size_t index, const char *format, ...) ATTR_PRINTF(3,4);
+ void SetSize(size_t size);
+ QueryResult* GetResult(size_t index);
+ void SetResult(size_t index, QueryResult *result);
+ void Execute(MaNGOS::IQueryCallback * callback, SqlDelayThread *thread, SqlResultQueue *queue);
+};
+
+class SqlQueryHolderEx : public SqlOperation
+{
+ private:
+ SqlQueryHolder * m_holder;
+ MaNGOS::IQueryCallback * m_callback;
+ SqlResultQueue * m_queue;
+ public:
+ SqlQueryHolderEx(SqlQueryHolder *holder, MaNGOS::IQueryCallback * callback, SqlResultQueue * queue)
+ : m_holder(holder), m_callback(callback), m_queue(queue) {}
+ void Execute(Database *db);
+};
+#endif //__SQLOPERATIONS_H
diff --git a/src/shared/Database/dbcfile.cpp b/src/shared/Database/dbcfile.cpp
new file mode 100644
index 00000000000..2521ab22614
--- /dev/null
+++ b/src/shared/Database/dbcfile.cpp
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dbcfile.h"
+
+DBCFile::DBCFile()
+{
+ data = NULL;
+ fieldsOffset = NULL;
+}
+
+bool DBCFile::Load(const char *filename, const char *fmt)
+{
+
+ uint32 header;
+ if(data)
+ {
+ delete [] data;
+ data=NULL;
+ }
+ FILE * f=fopen(filename,"rb");
+ if(!f)return false;
+
+ fread(&header,4,1,f); // Number of records
+ EndianConvert(header);
+ if(header!=0x43424457)
+ {
+ //printf("not dbc file");
+ return false; //'WDBC'
+ }
+ fread(&recordCount,4,1,f); // Number of records
+ EndianConvert(recordCount);
+ fread(&fieldCount,4,1,f); // Number of fields
+ EndianConvert(fieldCount);
+ fread(&recordSize,4,1,f); // Size of a record
+ EndianConvert(recordSize);
+ fread(&stringSize,4,1,f); // String size
+ EndianConvert(stringSize);
+
+ fieldsOffset = new uint32[fieldCount];
+ fieldsOffset[0] = 0;
+ for(uint32 i = 1; i < fieldCount; i++)
+ {
+ fieldsOffset[i] = fieldsOffset[i - 1];
+ if (fmt[i - 1] == 'b' || fmt[i - 1] == 'X') // byte fields
+ fieldsOffset[i] += 1;
+ else // 4 byte fields (int32/float/strings)
+ fieldsOffset[i] += 4;
+ }
+
+ data = new unsigned char[recordSize*recordCount+stringSize];
+ stringTable = data + recordSize*recordCount;
+ fread(data,recordSize*recordCount+stringSize,1,f);
+ fclose(f);
+ return true;
+}
+
+DBCFile::~DBCFile()
+{
+ if(data)
+ delete [] data;
+ if(fieldsOffset)
+ delete [] fieldsOffset;
+}
+
+DBCFile::Record DBCFile::getRecord(size_t id)
+{
+ assert(data);
+ return Record(*this, data + id*recordSize);
+}
+
+uint32 DBCFile::GetFormatRecordSize(const char * format,int32* index_pos)
+{
+ uint32 recordsize = 0;
+ int32 i = -1;
+ for(uint32 x=0; format[x];++x)
+ switch(format[x])
+ {
+ case FT_FLOAT:
+ case FT_INT:
+ recordsize+=4;
+ break;
+ case FT_STRING:
+ recordsize+=sizeof(char*);
+ break;
+ case FT_SORT:
+ i=x;
+ break;
+ case FT_IND:
+ i=x;
+ recordsize+=4;
+ break;
+ case FT_BYTE:
+ recordsize += 1;
+ break;
+ }
+
+ if(index_pos)
+ *index_pos = i;
+
+ return recordsize;
+}
+
+char* DBCFile::AutoProduceData(const char* format, uint32& records, char**& indexTable)
+{
+ /*
+ format STRING, NA, FLOAT,NA,INT <=>
+ struct{
+ char* field0,
+ float field1,
+ int field2
+ }entry;
+
+ this func will generate entry[rows] data;
+ */
+
+ typedef char * ptr;
+ if(strlen(format)!=fieldCount)
+ return NULL;
+
+ //get struct size and index pos
+ int32 i;
+ uint32 recordsize=GetFormatRecordSize(format,&i);
+
+ if(i>=0)
+ {
+ uint32 maxi=0;
+ //find max index
+ for(uint32 y=0;y<recordCount;y++)
+ {
+ uint32 ind=getRecord(y).getUInt (i);
+ if(ind>maxi)maxi=ind;
+ }
+
+ ++maxi;
+ records=maxi;
+ indexTable=new ptr[maxi];
+ memset(indexTable,0,maxi*sizeof(ptr));
+ }
+ else
+ {
+ records = recordCount;
+ indexTable = new ptr[recordCount];
+ }
+
+ char* dataTable= new char[recordCount*recordsize];
+
+ uint32 offset=0;
+
+ for(uint32 y =0;y<recordCount;y++)
+ {
+ if(i>=0)
+ {
+ indexTable[getRecord(y).getUInt(i)]=&dataTable[offset];
+ }
+ else
+ indexTable[y]=&dataTable[offset];
+
+ for(uint32 x=0;x<fieldCount;x++)
+ {
+ switch(format[x])
+ {
+ case FT_FLOAT:
+ *((float*)(&dataTable[offset]))=getRecord(y).getFloat(x);
+ offset+=4;
+ break;
+ case FT_IND:
+ case FT_INT:
+ *((uint32*)(&dataTable[offset]))=getRecord(y).getUInt(x);
+ offset+=4;
+ break;
+ case FT_BYTE:
+ *((uint8*)(&dataTable[offset]))=getRecord(y).getUInt8(x);
+ offset+=1;
+ break;
+ case FT_STRING:
+ *((char**)(&dataTable[offset]))=NULL; // will be replaces non-empty or "" strings in AutoProduceStrings
+ offset+=sizeof(char*);
+ break;
+ }
+ }
+ }
+
+ return dataTable;
+}
+
+char* DBCFile::AutoProduceStrings(const char* format, char* dataTable)
+{
+ if(strlen(format)!=fieldCount)
+ return NULL;
+
+ char* stringPool= new char[stringSize];
+ memcpy(stringPool,stringTable,stringSize);
+
+ uint32 offset=0;
+
+ for(uint32 y =0;y<recordCount;y++)
+ {
+ for(uint32 x=0;x<fieldCount;x++)
+ switch(format[x])
+ {
+ case FT_FLOAT:
+ case FT_IND:
+ case FT_INT:
+ offset+=4;
+ break;
+ case FT_BYTE:
+ offset+=1;
+ break;
+ case FT_STRING:
+ // fill only not filled entries
+ char** slot = (char**)(&dataTable[offset]);
+ if(!*slot || !**slot)
+ {
+ const char * st = getRecord(y).getString(x);
+ *slot=stringPool+(st-(const char*)stringTable);
+ }
+ offset+=sizeof(char*);
+ break;
+ }
+ }
+
+ return stringPool;
+}
diff --git a/src/shared/Database/dbcfile.h b/src/shared/Database/dbcfile.h
new file mode 100644
index 00000000000..bc59914ce53
--- /dev/null
+++ b/src/shared/Database/dbcfile.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef DBCFILE_H
+#define DBCFILE_H
+#include "Platform/Define.h"
+#include "Utilities/ByteConverter.h"
+#include <cassert>
+
+enum
+{
+ FT_NA='x', //not used or unknown, 4 byte size
+ FT_NA_BYTE='X', //not used or unknown, byte
+ FT_STRING='s', //char*
+ FT_FLOAT='f', //float
+ FT_INT='i', //uint32
+ FT_BYTE='b', //uint8
+ FT_SORT='d', //sorted by this field, field is not included
+ FT_IND='n', //the same,but parsed to data
+ FT_LOGIC='l' //Logical (boolean)
+};
+
+class DBCFile
+{
+ public:
+ DBCFile();
+ ~DBCFile();
+
+ bool Load(const char *filename, const char *fmt);
+
+ class Record
+ {
+ public:
+ float getFloat(size_t field) const
+ {
+ assert(field < file.fieldCount);
+ float val = *reinterpret_cast<float*>(offset+file.GetOffset(field));
+ EndianConvert(val);
+ return val;
+ }
+ uint32 getUInt(size_t field) const
+ {
+ assert(field < file.fieldCount);
+ uint32 val = *reinterpret_cast<uint32*>(offset+file.GetOffset(field));
+ EndianConvert(val);
+ return val;
+ }
+ uint8 getUInt8(size_t field) const
+ {
+ assert(field < file.fieldCount);
+ return *reinterpret_cast<uint8*>(offset+file.GetOffset(field));
+ }
+
+ const char *getString(size_t field) const
+ {
+ assert(field < file.fieldCount);
+ size_t stringOffset = getUInt(field);
+ assert(stringOffset < file.stringSize);
+ return reinterpret_cast<char*>(file.stringTable + stringOffset);
+ }
+
+ private:
+ Record(DBCFile &file_, unsigned char *offset_): offset(offset_), file(file_) {}
+ unsigned char *offset;
+ DBCFile &file;
+
+ friend class DBCFile;
+
+ };
+
+ // Get record by id
+ Record getRecord(size_t id);
+ /// Get begin iterator over records
+
+ uint32 GetNumRows() const { return recordCount;}
+ uint32 GetCols() const { return fieldCount; }
+ uint32 GetOffset(size_t id) const { return (fieldsOffset != NULL && id < fieldCount) ? fieldsOffset[id] : 0; }
+ bool IsLoaded() {return (data!=NULL);}
+ char* AutoProduceData(const char* fmt, uint32& count, char**& indexTable);
+ char* AutoProduceStrings(const char* fmt, char* dataTable);
+ static uint32 GetFormatRecordSize(const char * format, int32 * index_pos = NULL);
+ private:
+
+ uint32 recordSize;
+ uint32 recordCount;
+ uint32 fieldCount;
+ uint32 stringSize;
+ uint32 *fieldsOffset;
+ unsigned char *data;
+ unsigned char *stringTable;
+};
+#endif