aboutsummaryrefslogtreecommitdiff
path: root/src/server/shared/DataStores
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2016-01-24 15:56:10 +0100
committerShauren <shauren.trinity@gmail.com>2016-05-20 23:46:17 +0200
commit5c2c9a684f1458da0cea1f3536622add77ef1324 (patch)
treed3a2a349e8bed9a31cf417ce93830d508ecea46b /src/server/shared/DataStores
parent65c0a0ee4d5c299f3caab04b6cb3fcd7a4a93e2e (diff)
Core/DataStores: Updated dbc/db2 to 7.0.1.20810
Diffstat (limited to 'src/server/shared/DataStores')
-rw-r--r--src/server/shared/DataStores/DB2SparseStorageLoader.cpp683
-rw-r--r--src/server/shared/DataStores/DB2SparseStorageLoader.h117
-rw-r--r--src/server/shared/DataStores/DB2StorageLoader.cpp180
-rw-r--r--src/server/shared/DataStores/DB2StorageLoader.h40
-rw-r--r--src/server/shared/DataStores/DB2Store.h226
-rw-r--r--src/server/shared/DataStores/DBCFileLoader.cpp20
-rw-r--r--src/server/shared/DataStores/DBStorageIterator.h7
7 files changed, 1137 insertions, 136 deletions
diff --git a/src/server/shared/DataStores/DB2SparseStorageLoader.cpp b/src/server/shared/DataStores/DB2SparseStorageLoader.cpp
new file mode 100644
index 00000000000..2e7e974cb5d
--- /dev/null
+++ b/src/server/shared/DataStores/DB2SparseStorageLoader.cpp
@@ -0,0 +1,683 @@
+/*
+ * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Common.h"
+#include "DB2SparseStorageLoader.h"
+#include "Database/DatabaseEnv.h"
+#include "Log.h"
+
+DB2SparseFileLoader::DB2SparseFileLoader()
+{
+ fileName = nullptr;
+
+ recordCount = 0;
+ fieldCount = 0;
+ recordSize = 0;
+ offsetsPos = 0;
+ tableHash = 0;
+ build = 0;
+ unk1 = 0;
+ minIndex = 0;
+ maxIndex = 0;
+ localeMask = 0;
+ copyIdSize = 0;
+
+ dataStart = 0;
+ data = nullptr;
+ offsets = nullptr;
+}
+
+bool DB2SparseFileLoader::Load(const char *filename)
+{
+ if (data)
+ {
+ delete[] data;
+ data = nullptr;
+ }
+
+ FILE* f = fopen(filename, "rb");
+ if (!f)
+ return false;
+
+ fileName = filename;
+ uint32 header;
+ if (fread(&header, 4, 1, f) != 1) // Signature
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(header);
+
+ if (header != 0x34424457)
+ {
+ fclose(f);
+ return false; //'WDB4'
+ }
+
+ if (fread(&recordCount, 4, 1, f) != 1) // Number of records
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(recordCount);
+
+ if (fread(&fieldCount, 4, 1, f) != 1) // Number of fields
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(fieldCount);
+
+ if (fread(&recordSize, 4, 1, f) != 1) // Size of a record
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(recordSize);
+
+ if (fread(&offsetsPos, 4, 1, f) != 1) // String size
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(offsetsPos);
+
+ if (fread(&tableHash, 4, 1, f) != 1) // Table hash
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(tableHash);
+
+ if (fread(&build, 4, 1, f) != 1) // Build
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(build);
+
+ if (fread(&unk1, 4, 1, f) != 1) // Unknown WDB2
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(unk1);
+
+ if (fread(&minIndex, 4, 1, f) != 1) // MinIndex WDB2
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(minIndex);
+
+ if (fread(&maxIndex, 4, 1, f) != 1) // MaxIndex WDB2
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(maxIndex);
+
+ if (fread(&localeMask, 4, 1, f) != 1) // Locales
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(localeMask);
+
+ if (fread(&copyIdSize, 4, 1, f) != 1)
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(copyIdSize);
+
+ if (fread(&metaFlags, 4, 1, f) != 1)
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(metaFlags);
+
+ dataStart = ftell(f);
+
+ data = new unsigned char[offsetsPos - dataStart];
+
+ if (fread(data, offsetsPos - dataStart, 1, f) != 1)
+ {
+ fclose(f);
+ return false;
+ }
+
+ offsets = new OffsetTableEntry[maxIndex - minIndex + 1];
+ if (fread(offsets, (maxIndex - minIndex + 1) * 6, 1, f) != 1)
+ {
+ fclose(f);
+ return false;
+ }
+
+ fclose(f);
+ return true;
+}
+
+DB2SparseFileLoader::~DB2SparseFileLoader()
+{
+ delete[] data;
+ delete[] offsets;
+}
+
+uint32 DB2SparseFileLoader::GetFormatRecordSize(const char * format)
+{
+ uint32 recordsize = 0;
+ for (uint32 x = 0; format[x]; ++x)
+ {
+ switch (format[x])
+ {
+ case FT_FLOAT:
+ case FT_INT:
+ recordsize += 4;
+ break;
+ case FT_STRING:
+ case FT_STRING_NOT_LOCALIZED:
+ recordsize += sizeof(char*);
+ break;
+ case FT_BYTE:
+ recordsize += 1;
+ break;
+ case FT_LONG:
+ recordsize += 8;
+ break;
+ case FT_SHORT:
+ recordsize += 2;
+ break;
+ }
+ }
+
+ return recordsize;
+}
+
+uint32 DB2SparseFileLoader::GetFormatStringFieldCount(const char* format)
+{
+ uint32 stringfields = 0;
+ for (uint32 x = 0; format[x]; ++x)
+ if (format[x] == FT_STRING || format[x] == FT_STRING_NOT_LOCALIZED)
+ ++stringfields;
+
+ return stringfields;
+}
+
+uint32 DB2SparseFileLoader::GetFormatLocalizedStringFieldCount(char const* format)
+{
+ uint32 stringfields = 0;
+ for (uint32 x = 0; format[x]; ++x)
+ if (format[x] == FT_STRING)
+ ++stringfields;
+
+ return stringfields;
+}
+
+static char const* const nullStr = "";
+
+char* DB2SparseFileLoader::AutoProduceData(const char* format, IndexTable const& indexTable, uint32 locale, std::vector<char*>& stringPool)
+{
+ typedef char* ptr;
+ if (strlen(format) != fieldCount)
+ return NULL;
+
+ //get struct size and index pos
+ uint32 recordsize = GetFormatRecordSize(format);
+
+ uint32 offsetCount = maxIndex - minIndex + 1;
+ uint32 records = 0;
+ uint32 expandedDataSize = 0;
+ for (uint32 i = 0; i < offsetCount; ++i)
+ {
+ if (offsets[i].FileOffset && offsets[i].RecordSize)
+ {
+ ++records;
+ expandedDataSize += offsets[i].RecordSize;
+ }
+ }
+
+ char* dataTable = new char[records * recordsize];
+
+ // we store flat holders pool as single memory block
+ std::size_t stringFields = GetFormatStringFieldCount(format);
+ std::size_t localizedStringFields = GetFormatLocalizedStringFieldCount(format);
+
+ // each string field at load have array of string for each locale
+ std::size_t stringHolderSize = sizeof(char*) * TOTAL_LOCALES;
+ std::size_t stringHoldersRecordPoolSize = localizedStringFields * stringHolderSize + (stringFields - localizedStringFields) * sizeof(char*);
+ std::size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * records;
+
+ char* stringHoldersPool = new char[stringHoldersPoolSize];
+ stringPool.push_back(stringHoldersPool);
+
+ // DB2 strings expected to have at least empty string
+ for (std::size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i)
+ ((char const**)stringHoldersPool)[i] = nullStr;
+
+ char* stringTable = new char[expandedDataSize - records * (recordsize - stringFields * sizeof(char*))];
+ memset(stringTable, 0, expandedDataSize - records * (recordsize - stringFields * sizeof(char*)));
+ stringPool.push_back(stringTable);
+ char* stringPtr = stringTable;
+
+ uint32 offset = 0;
+ uint32 recordNum = 0;
+ for (uint32 y = 0; y < offsetCount; ++y)
+ {
+ if (!offsets[y].FileOffset || !offsets[y].RecordSize)
+ continue;
+
+ indexTable.Insert(y + minIndex, &dataTable[offset]);
+ uint32 fieldOffset = 0;
+ uint32 stringFieldOffset = 0;
+ for (uint32 x = 0; x < fieldCount; x++)
+ {
+ switch (format[x])
+ {
+ case FT_FLOAT:
+ *((float*)(&dataTable[offset])) = *reinterpret_cast<float*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]);
+ offset += 4;
+ fieldOffset += 4;
+ break;
+ case FT_IND:
+ case FT_INT:
+ *((uint32*)(&dataTable[offset])) = *reinterpret_cast<uint32*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]);
+ offset += 4;
+ fieldOffset += 4;
+ break;
+ case FT_BYTE:
+ *((uint8*)(&dataTable[offset])) = *reinterpret_cast<uint8*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]);
+ offset += 1;
+ fieldOffset += 1;
+ break;
+ case FT_LONG:
+ *((uint64*)(&dataTable[offset])) = *reinterpret_cast<uint64*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]);
+ offset += 8;
+ fieldOffset += 8;
+ break;
+ case FT_SHORT:
+ *((uint16*)(&dataTable[offset])) = *reinterpret_cast<uint16*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]);
+ offset += 2;
+ fieldOffset += 2;
+ break;
+ case FT_STRING:
+ {
+ LocalizedString** slot = (LocalizedString**)(&dataTable[offset]);
+ *slot = (LocalizedString*)(&stringHoldersPool[stringHoldersRecordPoolSize * recordNum + stringFieldOffset]);
+ (*slot)->Str[locale] = stringPtr;
+ strcpy(stringPtr, (char*)&data[offsets[y].FileOffset - dataStart + fieldOffset]);
+ fieldOffset += strlen(stringPtr) + 1;
+ stringPtr += strlen(stringPtr) + 1;
+ stringFieldOffset += stringHolderSize;
+ offset += sizeof(LocalizedString*);
+ break;
+ }
+ case FT_STRING_NOT_LOCALIZED:
+ {
+ char const*** slot = (char const***)(&dataTable[offset]);
+ *slot = (char const**)(&stringHoldersPool[stringHoldersRecordPoolSize * recordNum + stringFieldOffset]);
+ **slot = stringPtr;
+ strcpy(stringPtr, (char*)&data[offsets[y].FileOffset - dataStart + fieldOffset]);
+ fieldOffset += strlen(stringPtr) + 1;
+ stringPtr += strlen(stringPtr) + 1;
+ ++stringFieldOffset;
+ offset += sizeof(char*);
+ break;
+ }
+ }
+ }
+
+ ++recordNum;
+ }
+
+ return dataTable;
+}
+
+char* DB2SparseFileLoader::AutoProduceStrings(const char* format, char* dataTable, uint32 locale)
+{
+ if (strlen(format) != fieldCount)
+ return nullptr;
+
+ if (!(localeMask & (1 << locale)))
+ {
+ char const* sep = "";
+ std::ostringstream str;
+ for (uint32 i = 0; i < TOTAL_LOCALES; ++i)
+ {
+ if (localeMask & (1 << i))
+ {
+ str << sep << localeNames[i];
+ sep = ", ";
+ }
+ }
+
+ TC_LOG_ERROR("", "Attempted to load %s which has locales %s as %s. Check if you placed your localized db2 files in correct directory.", fileName, str.str().c_str(), localeNames[locale]);
+ return nullptr;
+ }
+
+ uint32 offsetCount = maxIndex - minIndex + 1;
+ uint32 records = 0;
+ for (uint32 i = 0; i < offsetCount; ++i)
+ if (offsets[i].FileOffset && offsets[i].RecordSize)
+ ++records;
+
+ uint32 recordsize = GetFormatRecordSize(format);
+ std::size_t stringFields = GetFormatStringFieldCount(format);
+ char* stringTable = new char[offsetsPos - dataStart - records * (recordsize - stringFields * sizeof(char*))];
+ memset(stringTable, 0, offsetsPos - dataStart - records * (recordsize - stringFields * sizeof(char*)));
+ char* stringPtr = stringTable;
+
+ uint32 offset = 0;
+
+ for (uint32 y = 0; y < offsetCount; y++)
+ {
+ if (!offsets[y].FileOffset || !offsets[y].RecordSize)
+ continue;
+
+ uint32 fieldOffset;
+ for (uint32 x = 0; x < fieldCount; x++)
+ {
+ switch (format[x])
+ {
+ case FT_FLOAT:
+ case FT_IND:
+ case FT_INT:
+ offset += 4;
+ fieldOffset += 4;
+ break;
+ case FT_BYTE:
+ offset += 1;
+ fieldOffset += 1;
+ break;
+ case FT_LONG:
+ offset += 8;
+ fieldOffset += 8;
+ break;
+ case FT_SHORT:
+ offset += 2;
+ fieldOffset += 2;
+ break;
+ case FT_STRING:
+ {
+ // fill only not filled entries
+ LocalizedString* db2str = *(LocalizedString**)(&dataTable[offset]);
+ db2str->Str[locale] = stringPtr;
+ strcpy(stringPtr, (char*)&data[offsets[y].FileOffset - dataStart + fieldOffset]);
+ fieldOffset += strlen(stringPtr) + 1;
+ stringPtr += strlen(stringPtr) + 1;
+ offset += sizeof(char*);
+ break;
+ }
+ case FT_STRING_NOT_LOCALIZED:
+ {
+ char** db2str = (char**)(&dataTable[offset]);
+ *db2str = stringPtr;
+ strcpy(stringPtr, (char*)&data[offsets[y].FileOffset - dataStart + fieldOffset]);
+ fieldOffset += strlen(stringPtr) + 1;
+ stringPtr += strlen(stringPtr) + 1;
+ offset += sizeof(char*);
+ break;
+ }
+ }
+ }
+ }
+
+ return stringTable;
+}
+
+char* DB2SparseDatabaseLoader::Load(const char* format, HotfixDatabaseStatements preparedStatement, IndexTable const& indexTable, std::vector<char*>& stringPool)
+{
+ // Even though this query is executed only once, prepared statement is used to send data from mysql server in binary format
+ PreparedQueryResult result = HotfixDatabase.Query(HotfixDatabase.GetPreparedStatement(preparedStatement));
+ if (!result)
+ return nullptr;
+
+ uint32 const fieldCount = strlen(format);
+ if (fieldCount != result->GetFieldCount())
+ return nullptr;
+
+ // get struct size and index pos
+ uint32 recordSize = DB2SparseFileLoader::GetFormatRecordSize(format);
+
+ // we store flat holders pool as single memory block
+ std::size_t stringFields = DB2SparseFileLoader::GetFormatStringFieldCount(format);
+ std::size_t localizedStringFields = DB2SparseFileLoader::GetFormatLocalizedStringFieldCount(format);
+
+ // each string field at load have array of string for each locale
+ std::size_t stringHolderSize = sizeof(char*) * TOTAL_LOCALES;
+ std::size_t stringHoldersRecordPoolSize = localizedStringFields * stringHolderSize + (stringFields - localizedStringFields) * sizeof(char*);
+
+ char* stringHolders = nullptr;
+ if (stringFields)
+ {
+ std::size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * result->GetRowCount();
+ stringHolders = new char[stringHoldersPoolSize];
+ stringPool.push_back(stringHolders);
+
+ // DB2 strings expected to have at least empty string
+ for (std::size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i)
+ ((char const**)stringHolders)[i] = nullStr;
+ }
+
+ char* tempDataTable = new char[result->GetRowCount() * recordSize];
+ uint32* newIndexes = new uint32[result->GetRowCount()];
+ uint32 rec = 0;
+ uint32 newRecords = 0;
+
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 offset = 0;
+ uint32 stringFieldOffset = 0;
+
+ uint32 indexValue = fields[0].GetUInt32();
+
+ // Attempt to overwrite existing data
+ char* dataValue = indexTable.Get(indexValue);
+ if (!dataValue)
+ {
+ newIndexes[newRecords] = indexValue;
+ dataValue = &tempDataTable[newRecords++ * recordSize];
+ }
+
+ for (uint32 f = 0; f < fieldCount; f++)
+ {
+ switch (format[f])
+ {
+ case FT_FLOAT:
+ *((float*)(&dataValue[offset])) = fields[f].GetFloat();
+ offset += 4;
+ break;
+ case FT_IND:
+ case FT_INT:
+ *((int32*)(&dataValue[offset])) = fields[f].GetInt32();
+ offset += 4;
+ break;
+ case FT_BYTE:
+ *((int8*)(&dataValue[offset])) = fields[f].GetInt8();
+ offset += 1;
+ break;
+ case FT_LONG:
+ *((int64*)(&dataValue[offset])) = fields[f].GetInt64();
+ offset += 8;
+ break;
+ case FT_SHORT:
+ *((int16*)(&dataValue[offset])) = fields[f].GetInt16();
+ offset += 2;
+ break;
+ case FT_STRING:
+ {
+ LocalizedString** slot = (LocalizedString**)(&dataValue[offset]);
+ *slot = (LocalizedString*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringFieldOffset]);
+ ASSERT(*slot);
+
+ // Value in database in main table field must be for enUS locale
+ if (char* str = AddString(&(*slot)->Str[LOCALE_enUS], fields[f].GetString()))
+ stringPool.push_back(str);
+
+ stringFieldOffset += stringHolderSize;
+ offset += sizeof(char*);
+ break;
+ }
+ case FT_STRING_NOT_LOCALIZED:
+ {
+ char const** slot = (char const**)(&dataValue[offset]);
+ *slot = (char*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringFieldOffset]);
+ ASSERT(*slot);
+
+ // Value in database in main table field must be for enUS locale
+ if (char* str = AddString(slot, fields[f].GetString()))
+ stringPool.push_back(str);
+
+ ++stringFieldOffset;
+ offset += sizeof(char*);
+ break;
+ }
+ }
+ }
+
+ ASSERT(offset == recordSize);
+ ++rec;
+ } while (result->NextRow());
+
+ if (!newRecords)
+ {
+ delete[] tempDataTable;
+ delete[] newIndexes;
+ return nullptr;
+ }
+
+ // Compact new data table to only contain new records not previously loaded from file
+ char* dataTable = new char[newRecords * recordSize];
+ memcpy(dataTable, tempDataTable, newRecords * recordSize);
+
+ // insert new records to index table
+ for (uint32 i = 0; i < newRecords; ++i)
+ indexTable.Insert(newIndexes[i], &dataTable[i * recordSize]);
+
+ delete[] tempDataTable;
+ delete[] newIndexes;
+
+ return dataTable;
+}
+
+void DB2SparseDatabaseLoader::LoadStrings(const char* format, HotfixDatabaseStatements preparedStatement, uint32 locale, IndexTable const& indexTable, std::vector<char*>& stringPool)
+{
+ PreparedStatement* stmt = HotfixDatabase.GetPreparedStatement(preparedStatement);
+ stmt->setString(0, localeNames[locale]);
+ PreparedQueryResult result = HotfixDatabase.Query(stmt);
+ if (!result)
+ return;
+
+ size_t stringFields = DB2SparseFileLoader::GetFormatLocalizedStringFieldCount(format);
+ if (result->GetFieldCount() != stringFields + 1 /*ID*/)
+ return;
+
+ uint32 const fieldCount = strlen(format);
+ uint32 recordSize = DB2SparseFileLoader::GetFormatRecordSize(format);
+ ASSERT(0 >= 0, "DB2Storage must be indexed to load localized strings");
+
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 offset = 0;
+ uint32 stringFieldNumInRecord = 0;
+ uint32 indexValue = fields[0].GetUInt32();
+
+ // Attempt to overwrite existing data
+ if (char* dataValue = indexTable.Get(indexValue))
+ {
+ 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_LONG:
+ offset += 8;
+ break;
+ case FT_SHORT:
+ offset += 2;
+ break;
+ case FT_STRING:
+ {
+ // fill only not filled entries
+ LocalizedString* db2str = *(LocalizedString**)(&dataValue[offset]);
+ if (db2str->Str[locale] == nullStr)
+ if (char* str = AddString(&db2str->Str[locale], fields[1 + stringFieldNumInRecord].GetString()))
+ stringPool.push_back(str);
+
+ ++stringFieldNumInRecord;
+ offset += sizeof(char*);
+ break;
+ }
+ }
+ }
+
+ ASSERT(offset == recordSize);
+ }
+ else
+ TC_LOG_ERROR("sql.sql", "Hotfix locale table for storage %s references row that does not exist %u!", _storageName.c_str(), indexValue);
+
+ } while (result->NextRow());
+
+ return;
+}
+
+char* DB2SparseDatabaseLoader::AddString(char const** holder, std::string const& value)
+{
+ if (!value.empty())
+ {
+ std::size_t existingLength = strlen(*holder);
+ if (existingLength >= value.length())
+ {
+ // Reuse existing storage if there is enough space
+ char* str = const_cast<char*>(*holder);
+ memcpy(str, value.c_str(), value.length());
+ str[value.length()] = '\0';
+ return nullptr;
+ }
+
+ char* str = new char[value.length() + 1];
+ memcpy(str, value.c_str(), value.length());
+ str[value.length()] = '\0';
+ *holder = str;
+ return str;
+ }
+
+ return nullptr;
+}
diff --git a/src/server/shared/DataStores/DB2SparseStorageLoader.h b/src/server/shared/DataStores/DB2SparseStorageLoader.h
new file mode 100644
index 00000000000..13f31e12d56
--- /dev/null
+++ b/src/server/shared/DataStores/DB2SparseStorageLoader.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DB2_SPARSE_FILE_LOADER_H
+#define DB2_SPARSE_FILE_LOADER_H
+
+#include "Define.h"
+#include "Utilities/ByteConverter.h"
+#include "Implementation/HotfixDatabase.h"
+#include <unordered_map>
+#include <vector>
+
+class IndexTable
+{
+public:
+ virtual void Insert(uint32 index, char* data) const = 0;
+ virtual char* Get(uint32 index) const = 0;
+};
+
+template<typename T>
+class IndexTableAdapter : public IndexTable
+{
+public:
+ IndexTableAdapter(std::unordered_map<uint32, T const*>& indexTable) : _indexTable(indexTable) { }
+
+ void Insert(uint32 index, char* data) const override
+ {
+ _indexTable[index] = (T const*)data;
+ }
+
+ char* Get(uint32 index) const override
+ {
+ auto itr = _indexTable.find(index);
+ if (itr != _indexTable.end())
+ return (char*)itr->second;
+ return nullptr;
+ }
+
+private:
+ std::unordered_map<uint32, T const*>& _indexTable;
+};
+
+class DB2SparseFileLoader
+{
+ public:
+ DB2SparseFileLoader();
+ ~DB2SparseFileLoader();
+
+ bool Load(const char *filename);
+
+ uint32 GetNumRows() const { return recordCount; }
+ uint32 GetCols() const { return fieldCount; }
+ uint32 GetHash() const { return tableHash; }
+ bool IsLoaded() const { return (data != NULL); }
+ char* AutoProduceData(const char* fmt, IndexTable const& indexTable, uint32 locale, std::vector<char*>& stringPool);
+ char* AutoProduceStrings(const char* fmt, char* dataTable, uint32 locale);
+ static uint32 GetFormatRecordSize(const char * format);
+ static uint32 GetFormatStringFieldCount(const char * format);
+ static uint32 GetFormatLocalizedStringFieldCount(const char * format);
+private:
+#pragma pack(push, 1)
+ struct OffsetTableEntry
+ {
+ uint32 FileOffset;
+ uint16 RecordSize;
+ };
+#pragma pack(pop)
+
+ char const* fileName;
+
+ // WDB2 / WCH2 fields
+ uint32 recordSize;
+ uint32 recordCount;
+ uint32 fieldCount;
+ uint32 offsetsPos;
+ uint32 tableHash;
+ uint32 build;
+ uint32 unk1;
+ uint32 minIndex;
+ uint32 maxIndex;
+ uint32 localeMask;
+ uint32 copyIdSize;
+ uint32 metaFlags;
+
+ uint32 dataStart;
+ unsigned char* data;
+ OffsetTableEntry* offsets;
+};
+
+class DB2SparseDatabaseLoader
+{
+public:
+ explicit DB2SparseDatabaseLoader(std::string const& storageName) : _storageName(storageName) { }
+
+ char* Load(const char* format, HotfixDatabaseStatements preparedStatement, IndexTable const& indexTable, std::vector<char*>& stringPool);
+ void LoadStrings(const char* format, HotfixDatabaseStatements preparedStatement, uint32 locale, IndexTable const& indexTable, std::vector<char*>& stringPool);
+ static char* AddString(char const** holder, std::string const& value);
+
+private:
+ std::string _storageName;
+};
+
+#endif
diff --git a/src/server/shared/DataStores/DB2StorageLoader.cpp b/src/server/shared/DataStores/DB2StorageLoader.cpp
index d2be433806f..d101d12a52e 100644
--- a/src/server/shared/DataStores/DB2StorageLoader.cpp
+++ b/src/server/shared/DataStores/DB2StorageLoader.cpp
@@ -23,22 +23,25 @@
DB2FileLoader::DB2FileLoader()
{
fileName = nullptr;
+
recordSize = 0;
recordCount = 0;
fieldCount = 0;
stringSize = 0;
- fieldsOffset = nullptr;
- data = nullptr;
- stringTable = nullptr;
-
tableHash = 0;
build = 0;
-
unk1 = 0;
minIndex = 0;
maxIndex = 0;
localeMask = 0;
- unk5 = 0;
+ copyIdSize = 0;
+
+ fieldsOffset = nullptr;
+ data = nullptr;
+ stringTable = nullptr;
+ idTable = nullptr;
+ idTableSize = 0;
+ copyTable = nullptr;
}
bool DB2FileLoader::Load(const char *filename, const char *fmt)
@@ -55,7 +58,7 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
fileName = filename;
uint32 header;
- if (fread(&header, 4, 1, f) != 1) // Signature
+ if (fread(&header, 4, 1, f) != 1) // Signature
{
fclose(f);
return false;
@@ -63,13 +66,13 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
EndianConvert(header);
- if (header != 0x32424457)
+ if (header != 0x34424457)
{
fclose(f);
- return false; //'WDB2'
+ return false; //'WDB4'
}
- if (fread(&recordCount, 4, 1, f) != 1) // Number of records
+ if (fread(&recordCount, 4, 1, f) != 1) // Number of records
{
fclose(f);
return false;
@@ -77,7 +80,7 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
EndianConvert(recordCount);
- if (fread(&fieldCount, 4, 1, f) != 1) // Number of fields
+ if (fread(&fieldCount, 4, 1, f) != 1) // Number of fields
{
fclose(f);
return false;
@@ -85,7 +88,7 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
EndianConvert(fieldCount);
- if (fread(&recordSize, 4, 1, f) != 1) // Size of a record
+ if (fread(&recordSize, 4, 1, f) != 1) // Size of a record
{
fclose(f);
return false;
@@ -93,7 +96,7 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
EndianConvert(recordSize);
- if (fread(&stringSize, 4, 1, f) != 1) // String size
+ if (fread(&stringSize, 4, 1, f) != 1) // String size
{
fclose(f);
return false;
@@ -101,8 +104,7 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
EndianConvert(stringSize);
- /* NEW WDB2 FIELDS*/
- if (fread(&tableHash, 4, 1, f) != 1) // Table hash
+ if (fread(&tableHash, 4, 1, f) != 1) // Table hash
{
fclose(f);
return false;
@@ -110,7 +112,7 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
EndianConvert(tableHash);
- if (fread(&build, 4, 1, f) != 1) // Build
+ if (fread(&build, 4, 1, f) != 1) // Build
{
fclose(f);
return false;
@@ -118,7 +120,7 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
EndianConvert(build);
- if (fread(&unk1, 4, 1, f) != 1) // Unknown WDB2
+ if (fread(&unk1, 4, 1, f) != 1) // Unknown WDB2
{
fclose(f);
return false;
@@ -126,7 +128,7 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
EndianConvert(unk1);
- if (fread(&minIndex, 4, 1, f) != 1) // MinIndex WDB2
+ if (fread(&minIndex, 4, 1, f) != 1) // MinIndex WDB2
{
fclose(f);
return false;
@@ -134,7 +136,7 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
EndianConvert(minIndex);
- if (fread(&maxIndex, 4, 1, f) != 1) // MaxIndex WDB2
+ if (fread(&maxIndex, 4, 1, f) != 1) // MaxIndex WDB2
{
fclose(f);
return false;
@@ -142,7 +144,7 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
EndianConvert(maxIndex);
- if (fread(&localeMask, 4, 1, f) != 1) // Locales
+ if (fread(&localeMask, 4, 1, f) != 1) // Locales
{
fclose(f);
return false;
@@ -150,18 +152,26 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
EndianConvert(localeMask);
- if (fread(&unk5, 4, 1, f) != 1) // Unknown WDB2
+ if (fread(&copyIdSize, 4, 1, f) != 1)
{
fclose(f);
return false;
}
- EndianConvert(unk5);
+ EndianConvert(copyIdSize);
- if (maxIndex != 0)
+ if (fread(&metaFlags, 4, 1, f) != 1)
{
- int32 diff = maxIndex - minIndex + 1;
- fseek(f, diff * 4 + diff * 2, SEEK_CUR); // diff * 4: an index for rows, diff * 2: a memory allocation bank
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(metaFlags);
+
+ if (fmt[0] == FT_SORT)
+ {
+ idTableSize = recordCount * sizeof(uint32);
+ ++fmt;
}
fieldsOffset = new uint32[fieldCount];
@@ -173,6 +183,8 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
fieldsOffset[i] += 1;
else if (fmt[i - 1] == FT_LONG)
fieldsOffset[i] += 8;
+ else if (fmt[i - 1] == FT_SHORT)
+ fieldsOffset[i] += 2;
else // 4 byte fields (int32/float/strings)
fieldsOffset[i] += 4;
}
@@ -186,29 +198,49 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
return false;
}
+ if (idTableSize)
+ {
+ idTable = new unsigned char[idTableSize];
+ if (fread(idTable, idTableSize, 1, f) != 1)
+ {
+ fclose(f);
+ return false;
+ }
+ }
+
+ if (copyIdSize)
+ {
+ copyTable = new unsigned char[copyIdSize];
+ if (fread(copyTable, copyIdSize, 1, f) != 1)
+ {
+ fclose(f);
+ return false;
+ }
+ }
+
fclose(f);
return true;
}
DB2FileLoader::~DB2FileLoader()
{
- if (data)
- delete [] data;
- if (fieldsOffset)
- delete [] fieldsOffset;
+ delete[] data;
+ delete[] idTable;
+ delete[] copyTable;
+ delete[] fieldsOffset;
}
DB2FileLoader::Record DB2FileLoader::getRecord(size_t id)
{
assert(data);
- return Record(*this, data + id*recordSize);
+ return Record(*this, data + id * recordSize);
}
uint32 DB2FileLoader::GetFormatRecordSize(const char * format, int32* index_pos)
{
uint32 recordsize = 0;
int32 i = -1;
- for (uint32 x=0; format[x]; ++x)
+ for (uint32 x = 0; format[x]; ++x)
{
switch (format[x])
{
@@ -233,6 +265,9 @@ uint32 DB2FileLoader::GetFormatRecordSize(const char * format, int32* index_pos)
case FT_LONG:
recordsize += 8;
break;
+ case FT_SHORT:
+ recordsize += 2;
+ break;
}
}
@@ -264,8 +299,8 @@ uint32 DB2FileLoader::GetFormatLocalizedStringFieldCount(char const* format)
char* DB2FileLoader::AutoProduceData(const char* format, uint32& records, char**& indexTable)
{
- typedef char * ptr;
- if (strlen(format) != fieldCount)
+ typedef char* ptr;
+ if (strlen(format) != fieldCount + (format[0] == FT_SORT ? 1 : 0))
return NULL;
//get struct size and index pos
@@ -276,9 +311,28 @@ char* DB2FileLoader::AutoProduceData(const char* format, uint32& records, char**
{
uint32 maxi = 0;
//find max index
- for (uint32 y = 0; y < recordCount; y++)
+ if (!idTableSize)
+ {
+ for (uint32 y = 0; y < recordCount; ++y)
+ {
+ uint32 ind = getRecord(y).getUInt(indexField);
+ if (ind > maxi)
+ maxi = ind;
+ }
+ }
+ else
{
- uint32 ind = getRecord(y).getUInt(indexField);
+ ASSERT(indexField == 0);
+ for (uint32 y = 0; y < recordCount; ++y)
+ {
+ uint32 ind = ((uint32*)idTable)[y];
+ if (ind > maxi)
+ maxi = ind;
+ }
+ }
+ for (uint32 y = 0; y < copyIdSize; y += 8)
+ {
+ uint32 ind = *((uint32*)(copyTable + y));
if (ind > maxi)
maxi = ind;
}
@@ -290,18 +344,25 @@ char* DB2FileLoader::AutoProduceData(const char* format, uint32& records, char**
}
else
{
+ ASSERT(!copyIdSize, "Storage %s uses id copy table - must be indexed!", fileName);
records = recordCount;
indexTable = new ptr[recordCount];
}
- char* dataTable = new char[recordCount * recordsize];
+ char* dataTable = new char[(recordCount + (copyIdSize / 8)) * recordsize];
uint32 offset = 0;
+ if (idTableSize)
+ {
+ ASSERT(format[0] == 'd');
+ ++format;
+ }
+
for (uint32 y = 0; y < recordCount; y++)
{
if (indexField >= 0)
- indexTable[getRecord(y).getUInt(indexField)] = &dataTable[offset];
+ indexTable[!idTableSize ? getRecord(y).getUInt(indexField) : ((uint32*)idTable)[y]] = &dataTable[offset];
else
indexTable[y] = &dataTable[offset];
@@ -326,6 +387,10 @@ char* DB2FileLoader::AutoProduceData(const char* format, uint32& records, char**
*((uint64*)(&dataTable[offset])) = getRecord(y).getUInt64(x);
offset += 8;
break;
+ case FT_SHORT:
+ *((uint16*)(&dataTable[offset])) = getRecord(y).getUInt16(x);
+ offset += 2;
+ break;
case FT_STRING:
case FT_STRING_NOT_LOCALIZED:
*((char**)(&dataTable[offset])) = nullptr; // will be replaces non-empty or "" strings in AutoProduceStrings
@@ -335,6 +400,20 @@ char* DB2FileLoader::AutoProduceData(const char* format, uint32& records, char**
}
}
+ uint32* copyIds = (uint32*)copyTable;
+ for (uint32 c = 0; c < copyIdSize / 4; c += 2)
+ {
+ uint32 to = copyIds[c];
+ uint32 from = copyIds[c + 1];
+
+ if (from && from < records && indexTable[from])
+ {
+ indexTable[to] = &dataTable[offset];
+ memcpy(indexTable[to], indexTable[from], recordsize);
+ offset += recordsize;
+ }
+ }
+
return dataTable;
}
@@ -342,7 +421,7 @@ static char const* const nullStr = "";
char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* dataTable)
{
- if (strlen(format) != fieldCount)
+ if (strlen(format) != fieldCount + (format[0] == FT_SORT ? 1 : 0))
return nullptr;
// we store flat holders pool as single memory block
@@ -365,6 +444,9 @@ char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* da
uint32 offset = 0;
+ if (idTableSize)
+ ++format;
+
// assign string holders to string field slots
for (uint32 y = 0; y < recordCount; y++)
{
@@ -385,6 +467,9 @@ char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* da
case FT_LONG:
offset += 8;
break;
+ case FT_SHORT:
+ offset += 2;
+ break;
case FT_STRING:
case FT_STRING_NOT_LOCALIZED:
{
@@ -411,7 +496,7 @@ char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* da
char* DB2FileLoader::AutoProduceStrings(const char* format, char* dataTable, uint32 locale)
{
- if (strlen(format) != fieldCount)
+ if (strlen(format) != fieldCount + (format[0] == FT_SORT ? 1 : 0))
return nullptr;
if (!(localeMask & (1 << locale)))
@@ -436,6 +521,9 @@ char* DB2FileLoader::AutoProduceStrings(const char* format, char* dataTable, uin
uint32 offset = 0;
+ if (idTableSize)
+ ++format;
+
for (uint32 y = 0; y < recordCount; y++)
{
for (uint32 x = 0; x < fieldCount; x++)
@@ -453,6 +541,9 @@ char* DB2FileLoader::AutoProduceStrings(const char* format, char* dataTable, uin
case FT_LONG:
offset += 8;
break;
+ case FT_SHORT:
+ offset += 2;
+ break;
case FT_STRING:
{
// fill only not filled entries
@@ -481,7 +572,7 @@ char* DB2FileLoader::AutoProduceStrings(const char* format, char* dataTable, uin
return stringPool;
}
-char* DB2DatabaseLoader::Load(const char* format, HotfixDatabaseStatements preparedStatement, uint32& records, char**& indexTable, char*& stringHolders, std::list<char*>& stringPool)
+char* DB2DatabaseLoader::Load(const char* format, HotfixDatabaseStatements preparedStatement, uint32& records, char**& indexTable, char*& stringHolders, std::vector<char*>& stringPool)
{
// Even though this query is executed only once, prepared statement is used to send data from mysql server in binary format
PreparedQueryResult result = HotfixDatabase.Query(HotfixDatabase.GetPreparedStatement(preparedStatement));
@@ -582,6 +673,10 @@ char* DB2DatabaseLoader::Load(const char* format, HotfixDatabaseStatements prepa
*((int64*)(&dataValue[offset])) = fields[f].GetInt64();
offset += 8;
break;
+ case FT_SHORT:
+ *((int16*)(&dataValue[offset])) = fields[f].GetInt16();
+ offset += 2;
+ break;
case FT_STRING:
{
LocalizedString** slot = (LocalizedString**)(&dataValue[offset]);
@@ -640,7 +735,7 @@ char* DB2DatabaseLoader::Load(const char* format, HotfixDatabaseStatements prepa
return dataTable;
}
-void DB2DatabaseLoader::LoadStrings(const char* format, HotfixDatabaseStatements preparedStatement, uint32 locale, char**& indexTable, std::list<char*>& stringPool)
+void DB2DatabaseLoader::LoadStrings(const char* format, HotfixDatabaseStatements preparedStatement, uint32 locale, char**& indexTable, std::vector<char*>& stringPool)
{
PreparedStatement* stmt = HotfixDatabase.GetPreparedStatement(preparedStatement);
stmt->setString(0, localeNames[locale]);
@@ -682,6 +777,9 @@ void DB2DatabaseLoader::LoadStrings(const char* format, HotfixDatabaseStatements
case FT_LONG:
offset += 8;
break;
+ case FT_SHORT:
+ offset += 2;
+ break;
case FT_STRING:
{
// fill only not filled entries
diff --git a/src/server/shared/DataStores/DB2StorageLoader.h b/src/server/shared/DataStores/DB2StorageLoader.h
index 41705c67f19..67525779ef5 100644
--- a/src/server/shared/DataStores/DB2StorageLoader.h
+++ b/src/server/shared/DataStores/DB2StorageLoader.h
@@ -22,7 +22,7 @@
#include "Utilities/ByteConverter.h"
#include "Implementation/HotfixDatabase.h"
#include <cassert>
-#include <list>
+#include <vector>
class TC_SHARED_API DB2FileLoader
{
@@ -61,6 +61,13 @@ class TC_SHARED_API DB2FileLoader
EndianConvert(val);
return val;
}
+ uint16 getUInt16(size_t field) const
+ {
+ assert(field < file.fieldCount);
+ uint16 val = *reinterpret_cast<uint16*>(offset + file.GetOffset(field));
+ EndianConvert(val);
+ return val;
+ }
const char *getString(size_t field) const
{
assert(field < file.fieldCount);
@@ -95,23 +102,26 @@ class TC_SHARED_API DB2FileLoader
private:
char const* fileName;
+ // WDB2 / WCH2 fields
uint32 recordSize;
uint32 recordCount;
uint32 fieldCount;
uint32 stringSize;
- uint32 *fieldsOffset;
- unsigned char *data;
- unsigned char *stringTable;
+ uint32 tableHash;
+ uint32 build;
+ uint32 unk1;
+ uint32 minIndex;
+ uint32 maxIndex;
+ uint32 localeMask;
+ uint32 copyIdSize;
+ uint32 metaFlags;
- // WDB2 / WCH2 fields
- uint32 tableHash; // WDB2
- uint32 build; // WDB2
-
- int unk1; // WDB2 (Unix time in WCH2)
- int minIndex; // WDB2
- int maxIndex; // WDB2 (index table)
- int localeMask; // WDB2
- int unk5; // WDB2
+ uint32 *fieldsOffset;
+ unsigned char* data;
+ unsigned char* stringTable;
+ unsigned char* idTable;
+ uint32 idTableSize;
+ unsigned char* copyTable;
};
class TC_SHARED_API DB2DatabaseLoader
@@ -119,8 +129,8 @@ class TC_SHARED_API DB2DatabaseLoader
public:
explicit DB2DatabaseLoader(std::string const& storageName) : _storageName(storageName) { }
- char* Load(const char* format, HotfixDatabaseStatements preparedStatement, uint32& records, char**& indexTable, char*& stringHolders, std::list<char*>& stringPool);
- void LoadStrings(const char* format, HotfixDatabaseStatements preparedStatement, uint32 locale, char**& indexTable, std::list<char*>& stringPool);
+ char* Load(const char* format, HotfixDatabaseStatements preparedStatement, uint32& records, char**& indexTable, char*& stringHolders, std::vector<char*>& stringPool);
+ void LoadStrings(const char* format, HotfixDatabaseStatements preparedStatement, uint32 locale, char**& indexTable, std::vector<char*>& stringPool);
static char* AddString(char const** holder, std::string const& value);
private:
diff --git a/src/server/shared/DataStores/DB2Store.h b/src/server/shared/DataStores/DB2Store.h
index 72271ce507b..570e8174a39 100644
--- a/src/server/shared/DataStores/DB2Store.h
+++ b/src/server/shared/DataStores/DB2Store.h
@@ -20,6 +20,7 @@
#include "Common.h"
#include "DB2StorageLoader.h"
+#include "DB2SparseStorageLoader.h"
#include "DBStorageIterator.h"
#include "ByteBuffer.h"
@@ -27,7 +28,16 @@
class DB2StorageBase
{
public:
- virtual ~DB2StorageBase() { }
+ DB2StorageBase(char const* fileName, char const* format, HotfixDatabaseStatements preparedStmtIndex)
+ : _tableHash(0), _fileName(fileName), _fieldCount(0), _format(format), _dataTable(nullptr), _dataTableEx(nullptr), _hotfixStatement(preparedStmtIndex) { }
+
+ virtual ~DB2StorageBase()
+ {
+ delete[] reinterpret_cast<char*>(_dataTable);
+ delete[] reinterpret_cast<char*>(_dataTableEx);
+ for (char* strings : _stringPool)
+ delete[] strings;
+ }
uint32 GetHash() const { return _tableHash; }
@@ -37,39 +47,20 @@ public:
virtual void EraseRecord(uint32 id) = 0;
-protected:
- uint32 _tableHash;
-};
+ std::string const& GetFileName() const { return _fileName; }
-template<class T>
-class DB2Storage : public DB2StorageBase
-{
- typedef std::list<char*> StringPoolList;
-public:
- typedef DBStorageIterator<T> iterator;
+ uint32 GetFieldCount() const { return _fieldCount; }
- DB2Storage(char const* fileName, char const* format, HotfixDatabaseStatements preparedStmtIndex)
- : _fileName(fileName), _indexTableSize(0), _fieldCount(0), _format(format), _dataTable(nullptr), _dataTableEx(nullptr), _hotfixStatement(preparedStmtIndex)
- {
- _indexTable.AsT = NULL;
- }
+ char const* GetFormat() const { return _format; }
- ~DB2Storage()
- {
- delete[] reinterpret_cast<char*>(_indexTable.AsT);
- delete[] reinterpret_cast<char*>(_dataTable);
- delete[] reinterpret_cast<char*>(_dataTableEx);
- for (char* stringPool : _stringPoolList)
- delete[] stringPool;
- }
+ virtual bool Load(std::string const& path, uint32 locale) = 0;
+ virtual bool LoadStringsFrom(std::string const& path, uint32 locale) = 0;
+ virtual void LoadFromDB() = 0;
+ virtual void LoadStringsFromDB(uint32 locale) = 0;
- bool HasRecord(uint32 id) const override { return id < _indexTableSize && _indexTable.AsT[id] != nullptr; }
- void WriteRecord(uint32 id, uint32 locale, ByteBuffer& buffer) const override
+protected:
+ void WriteRecordData(char const* entry, uint32 locale, ByteBuffer& buffer) const
{
- ASSERT(id < _indexTableSize);
- char const* entry = _indexTable.AsChar[id];
- ASSERT(entry);
-
std::size_t fields = strlen(_format);
for (uint32 i = 0; i < fields; ++i)
{
@@ -122,16 +113,48 @@ public:
}
}
+ uint32 _tableHash;
+ std::string _fileName;
+ uint32 _fieldCount;
+ char const* _format;
+ char* _dataTable;
+ char* _dataTableEx;
+ std::vector<char*> _stringPool;
+ HotfixDatabaseStatements _hotfixStatement;
+};
+
+template<class T>
+class DB2Storage : public DB2StorageBase
+{
+ static_assert(std::is_standard_layout<T>::value, "T in DB2Storage must have standard layout.");
+
+public:
+ typedef DBStorageIterator<T> iterator;
+
+ DB2Storage(char const* fileName, char const* format, HotfixDatabaseStatements preparedStmtIndex) : DB2StorageBase(fileName, format, preparedStmtIndex),
+ _indexTableSize(0)
+ {
+ _indexTable.AsT = NULL;
+ }
+
+ ~DB2Storage()
+ {
+ delete[] reinterpret_cast<char*>(_indexTable.AsT);
+ }
+
+ bool HasRecord(uint32 id) const override { return id < _indexTableSize && _indexTable.AsT[id] != nullptr; }
+ void WriteRecord(uint32 id, uint32 locale, ByteBuffer& buffer) const override
+ {
+ WriteRecordData(reinterpret_cast<char const*>(AssertEntry(id)), locale, buffer);
+ }
+
void EraseRecord(uint32 id) override { if (id < _indexTableSize) _indexTable.AsT[id] = nullptr; }
T const* LookupEntry(uint32 id) const { return (id >= _indexTableSize) ? nullptr : _indexTable.AsT[id]; }
T const* AssertEntry(uint32 id) const { return ASSERT_NOTNULL(LookupEntry(id)); }
- std::string const& GetFileName() const { return _fileName; }
uint32 GetNumRows() const { return _indexTableSize; }
- char const* GetFormat() const { return _format; }
- uint32 GetFieldCount() const { return _fieldCount; }
- bool Load(std::string const& path, uint32 locale)
+ bool Load(std::string const& path, uint32 locale) override
{
DB2FileLoader db2;
// Check if load was successful, only then continue
@@ -142,23 +165,23 @@ public:
_tableHash = db2.GetHash();
// load raw non-string data
- _dataTable = reinterpret_cast<T*>(db2.AutoProduceData(_format, _indexTableSize, _indexTable.AsChar));
+ _dataTable = db2.AutoProduceData(_format, _indexTableSize, _indexTable.AsChar);
// create string holders for loaded string fields
- if (char* stringHolders = db2.AutoProduceStringsArrayHolders(_format, (char*)_dataTable))
+ if (char* stringHolders = db2.AutoProduceStringsArrayHolders(_format, _dataTable))
{
- _stringPoolList.push_back(stringHolders);
+ _stringPool.push_back(stringHolders);
// load strings from db2 data
- if (char* stringBlock = db2.AutoProduceStrings(_format, (char*)_dataTable, locale))
- _stringPoolList.push_back(stringBlock);
+ if (char* stringBlock = db2.AutoProduceStrings(_format, _dataTable, locale))
+ _stringPool.push_back(stringBlock);
}
// error in db2 file at loading if NULL
return _indexTable.AsT != NULL;
}
- bool LoadStringsFrom(std::string const& path, uint32 locale)
+ bool LoadStringsFrom(std::string const& path, uint32 locale) override
{
// DB2 must be already loaded using Load
if (!_indexTable.AsT)
@@ -171,54 +194,129 @@ public:
// load strings from another locale db2 data
if (DB2FileLoader::GetFormatLocalizedStringFieldCount(_format))
- if (char* stringBlock = db2.AutoProduceStrings(_format, (char*)_dataTable, locale))
- _stringPoolList.push_back(stringBlock);
+ if (char* stringBlock = db2.AutoProduceStrings(_format, _dataTable, locale))
+ _stringPool.push_back(stringBlock);
return true;
}
- void LoadFromDB()
+ void LoadFromDB() override
{
char* extraStringHolders = nullptr;
- if (char* dataTable = DB2DatabaseLoader(_fileName).Load(_format, _hotfixStatement, _indexTableSize, _indexTable.AsChar, extraStringHolders, _stringPoolList))
- _dataTableEx = reinterpret_cast<T*>(dataTable);
-
+ _dataTableEx = DB2DatabaseLoader(_fileName).Load(_format, _hotfixStatement, _indexTableSize, _indexTable.AsChar, extraStringHolders, _stringPool);
if (extraStringHolders)
- _stringPoolList.push_back(extraStringHolders);
+ _stringPool.push_back(extraStringHolders);
}
- void LoadStringsFromDB(uint32 locale)
+ void LoadStringsFromDB(uint32 locale) override
{
if (!DB2FileLoader::GetFormatLocalizedStringFieldCount(_format))
return;
- DB2DatabaseLoader(_fileName).LoadStrings(_format, HotfixDatabaseStatements(_hotfixStatement + 1), locale, _indexTable.AsChar, _stringPoolList);
- }
-
- typedef bool(*SortFunc)(T const* left, T const* right);
-
- void Sort(SortFunc pred)
- {
- ASSERT(strpbrk(_format, "nd") == nullptr, "Only non-indexed storages can be sorted");
- std::sort(_indexTable.AsT, _indexTable.AsT + _indexTableSize, pred);
+ DB2DatabaseLoader(_fileName).LoadStrings(_format, HotfixDatabaseStatements(_hotfixStatement + 1), locale, _indexTable.AsChar, _stringPool);
}
iterator begin() { return iterator(_indexTable.AsT, _indexTableSize); }
iterator end() { return iterator(_indexTable.AsT, _indexTableSize, _indexTableSize); }
private:
- std::string _fileName;
- uint32 _indexTableSize;
- uint32 _fieldCount;
- char const* _format;
union
{
T** AsT;
char** AsChar;
} _indexTable;
- T* _dataTable;
- T* _dataTableEx;
- StringPoolList _stringPoolList;
- HotfixDatabaseStatements _hotfixStatement;
+ uint32 _indexTableSize;
+};
+
+template<class T>
+class DB2SparseStorage : public DB2StorageBase
+{
+ static_assert(std::is_pod<T>::value, "T in DB2SparseStorage must be POD-type.");
+
+public:
+ typedef typename std::unordered_map<uint32, T const*>::const_iterator iterator;
+
+ DB2SparseStorage(char const* fileName, char const* format, HotfixDatabaseStatements preparedStmtIndex)
+ : DB2StorageBase(fileName, format, preparedStmtIndex)
+ {
+ }
+
+ ~DB2SparseStorage()
+ {
+ }
+
+ bool HasRecord(uint32 id) const override { return _indexTable.count(id) > 0; }
+ void WriteRecord(uint32 id, uint32 locale, ByteBuffer& buffer) const override
+ {
+ WriteRecordData(reinterpret_cast<char const*>(AssertEntry(id)), locale, buffer);
+ }
+
+ void EraseRecord(uint32 id) override { _indexTable.erase(id); }
+
+ T const* LookupEntry(uint32 id) const
+ {
+ auto itr = _indexTable.find(id);
+ if (itr != _indexTable.end())
+ return itr->second;
+ return nullptr;
+ }
+
+ T const* AssertEntry(uint32 id) const { return ASSERT_NOTNULL(LookupEntry(id)); }
+
+ uint32 GetNumRows() const { return _indexTable.size(); }
+
+ bool Load(std::string const& path, uint32 locale) override
+ {
+ DB2SparseFileLoader db2;
+ // Check if load was successful, only then continue
+ if (!db2.Load((path + _fileName).c_str()))
+ return false;
+
+ _fieldCount = db2.GetCols();
+ _tableHash = db2.GetHash();
+
+ // load raw non-string data
+ _dataTable = db2.AutoProduceData(_format, IndexTableAdapter<T>(_indexTable), locale, _stringPool);
+
+ // error in db2 file at loading if NULL
+ return !_indexTable.empty();
+ }
+
+ bool LoadStringsFrom(std::string const& path, uint32 locale) override
+ {
+ // DB2 must be already loaded using Load
+ if (_indexTable.empty())
+ return false;
+
+ DB2SparseFileLoader db2;
+ // Check if load was successful, only then continue
+ if (!db2.Load((path + _fileName).c_str()))
+ return false;
+
+ // load strings from another locale db2 data
+ if (DB2SparseFileLoader::GetFormatLocalizedStringFieldCount(_format))
+ if (char* stringBlock = db2.AutoProduceStrings(_format, _dataTable, locale))
+ _stringPool.push_back(stringBlock);
+ return true;
+ }
+
+ void LoadFromDB() override
+ {
+ _dataTableEx = DB2SparseDatabaseLoader(_fileName).Load(_format, _hotfixStatement, IndexTableAdapter<T>(_indexTable), _stringPool);
+ }
+
+ void LoadStringsFromDB(uint32 locale) override
+ {
+ if (!DB2SparseFileLoader::GetFormatLocalizedStringFieldCount(_format))
+ return;
+
+ DB2SparseDatabaseLoader(_fileName).LoadStrings(_format, HotfixDatabaseStatements(_hotfixStatement + 1), locale, IndexTableAdapter<T>(_indexTable), _stringPool);
+ }
+
+ iterator begin() const { return _indexTable.begin(); }
+ iterator end() const { return _indexTable.end(); }
+
+private:
+ std::unordered_map<uint32, T const*> _indexTable;
};
#endif
diff --git a/src/server/shared/DataStores/DBCFileLoader.cpp b/src/server/shared/DataStores/DBCFileLoader.cpp
index 829c3708221..ec3a95f74b9 100644
--- a/src/server/shared/DataStores/DBCFileLoader.cpp
+++ b/src/server/shared/DataStores/DBCFileLoader.cpp
@@ -172,17 +172,6 @@ uint32 DBCFileLoader::GetFormatRecordSize(const char* format, int32* index_pos)
char* DBCFileLoader::AutoProduceData(const char* format, uint32& records, char**& indexTable, uint32 sqlRecordCount, uint32 sqlHighestIndex, char*& sqlDataTable)
{
- /*
- 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;
@@ -193,11 +182,11 @@ char* DBCFileLoader::AutoProduceData(const char* format, uint32& records, char**
if (i >= 0)
{
- uint32 maxi = 0;
+ int32 maxi = 0;
//find max index
for (uint32 y = 0; y < recordCount; ++y)
{
- uint32 ind = getRecord(y).getUInt(i);
+ int32 ind = int32(getRecord(y).getUInt(i));
if (ind > maxi)
maxi = ind;
}
@@ -224,7 +213,10 @@ char* DBCFileLoader::AutoProduceData(const char* format, uint32& records, char**
for (uint32 y = 0; y < recordCount; ++y)
{
if (i >= 0)
- indexTable[getRecord(y).getUInt(i)] = &dataTable[offset];
+ {
+ if (int32(getRecord(y).getUInt(i)) >= 0)
+ indexTable[getRecord(y).getUInt(i)] = &dataTable[offset];
+ }
else
indexTable[y] = &dataTable[offset];
diff --git a/src/server/shared/DataStores/DBStorageIterator.h b/src/server/shared/DataStores/DBStorageIterator.h
index 8148a2a5300..8e7d03f2756 100644
--- a/src/server/shared/DataStores/DBStorageIterator.h
+++ b/src/server/shared/DataStores/DBStorageIterator.h
@@ -35,8 +35,11 @@ public:
}
}
- T* operator->() { return _index[_pos]; }
- T* operator*() { return _index[_pos]; }
+ uint32 Key() const { return _pos; }
+ T const* Value() const { return _index[_pos]; }
+
+ T const* operator->() { return _index[_pos]; }
+ T const* operator*() { return _index[_pos]; }
bool operator==(DBStorageIterator const& right) const { /*ASSERT(_index == right._index, "Iterator belongs to a different container")*/ return _pos == right._pos; }
bool operator!=(DBStorageIterator const& right) const { return !(*this == right); }