aboutsummaryrefslogtreecommitdiff
path: root/src/server/shared
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/shared')
-rw-r--r--src/server/shared/DataStores/DB2Meta.cpp101
-rw-r--r--src/server/shared/DataStores/DB2Meta.h47
-rw-r--r--src/server/shared/DataStores/DB2SparseStorageLoader.cpp708
-rw-r--r--src/server/shared/DataStores/DB2SparseStorageLoader.h123
-rw-r--r--src/server/shared/DataStores/DB2StorageLoader.cpp648
-rw-r--r--src/server/shared/DataStores/DB2StorageLoader.h159
-rw-r--r--src/server/shared/DataStores/DB2Store.h315
-rw-r--r--src/server/shared/DataStores/DBCFileLoader.cpp325
-rw-r--r--src/server/shared/DataStores/DBCFileLoader.h105
-rw-r--r--src/server/shared/DataStores/DBCStore.h325
-rw-r--r--src/server/shared/DataStores/DBStorageIterator.h4
11 files changed, 1649 insertions, 1211 deletions
diff --git a/src/server/shared/DataStores/DB2Meta.cpp b/src/server/shared/DataStores/DB2Meta.cpp
new file mode 100644
index 00000000000..bf119b52150
--- /dev/null
+++ b/src/server/shared/DataStores/DB2Meta.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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 "DB2Meta.h"
+
+DB2Meta::DB2Meta(int32 indexField, uint32 fieldCount, uint32 layoutHash, char const* types, uint8 const* arraySizes)
+ : IndexField(indexField), FieldCount(fieldCount), LayoutHash(layoutHash), Types(types), ArraySizes(arraySizes)
+{
+}
+
+bool DB2Meta::HasIndexFieldInData() const
+{
+ return IndexField != -1;
+}
+
+uint32 DB2Meta::GetIndexField() const
+{
+ return IndexField == -1 ? 0 : uint32(IndexField);
+}
+
+uint32 DB2Meta::GetRecordSize() const
+{
+ uint32 size = 0;
+ for (uint32 i = 0; i < FieldCount; ++i)
+ {
+ for (uint8 j = 0; j < ArraySizes[i]; ++j)
+ {
+ switch (Types[i])
+ {
+ case FT_BYTE:
+ size += 1;
+ break;
+ case FT_SHORT:
+ size += 2;
+ break;
+ case FT_FLOAT:
+ case FT_INT:
+ size += 4;
+ break;
+ case FT_STRING:
+ case FT_STRING_NOT_LOCALIZED:
+ size += sizeof(char*);
+ break;
+ }
+ }
+ }
+
+ if (!HasIndexFieldInData())
+ size += 4;
+
+ return size;
+}
+
+uint32 DB2Meta::GetDbIndexField() const
+{
+ if (IndexField == -1)
+ return 0;
+
+ uint32 index = 0;
+ for (uint32 i = 0; i < FieldCount && i < uint32(IndexField); ++i)
+ index += ArraySizes[i];
+
+ return index;
+}
+
+uint32 DB2Meta::GetDbFieldCount() const
+{
+ uint32 fields = 0;
+ for (uint32 i = 0; i < FieldCount; ++i)
+ fields += ArraySizes[i];
+
+ if (!HasIndexFieldInData())
+ ++fields;
+
+ return fields;
+}
+
+uint32 DB2Meta::GetStringFieldCount(bool localizedOnly) const
+{
+ uint32 stringFields = 0;
+ for (uint32 i = 0; i < FieldCount; ++i)
+ if (Types[i] == FT_STRING || (Types[i] == FT_STRING_NOT_LOCALIZED && !localizedOnly))
+ for (uint8 j = 0; j < ArraySizes[i]; ++j)
+ ++stringFields;
+
+ return stringFields;
+}
diff --git a/src/server/shared/DataStores/DB2Meta.h b/src/server/shared/DataStores/DB2Meta.h
new file mode 100644
index 00000000000..2c165b52d86
--- /dev/null
+++ b/src/server/shared/DataStores/DB2Meta.h
@@ -0,0 +1,47 @@
+/*
+ * 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 DB2Meta_h__
+#define DB2Meta_h__
+
+#include "Define.h"
+
+struct DB2Meta
+{
+ DB2Meta(int32 indexField, uint32 fieldCount, uint32 layoutHash, char const* types, uint8 const* arraySizes);
+
+ bool HasIndexFieldInData() const;
+
+ // Returns field index for data loaded in our structures (ID field is appended in the front if not present in db2 file data section)
+ uint32 GetIndexField() const;
+
+ // Returns size of final loaded structure
+ uint32 GetRecordSize() const;
+
+ uint32 GetDbIndexField() const;
+ uint32 GetDbFieldCount() const;
+
+ uint32 GetStringFieldCount(bool localizedOnly) const;
+
+ int32 IndexField;
+ uint32 FieldCount;
+ uint32 LayoutHash;
+ char const* Types;
+ uint8 const* ArraySizes;
+};
+
+#endif // DB2Meta_h__
diff --git a/src/server/shared/DataStores/DB2SparseStorageLoader.cpp b/src/server/shared/DataStores/DB2SparseStorageLoader.cpp
new file mode 100644
index 00000000000..c6e1c495b00
--- /dev/null
+++ b/src/server/shared/DataStores/DB2SparseStorageLoader.cpp
@@ -0,0 +1,708 @@
+/*
+ * 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 "DatabaseEnv.h"
+#include "Log.h"
+
+DB2SparseFileLoader::DB2SparseFileLoader()
+{
+ fileName = nullptr;
+ meta = nullptr;
+
+ recordCount = 0;
+ fieldCount = 0;
+ recordSize = 0;
+ offsetsPos = 0;
+ tableHash = 0;
+ layoutHash = 0;
+ minIndex = 0;
+ maxIndex = 0;
+ localeMask = 0;
+ copyIdSize = 0;
+
+ dataStart = 0;
+ data = nullptr;
+ offsets = nullptr;
+ fields = nullptr;
+}
+
+bool DB2SparseFileLoader::Load(const char *filename, DB2Meta const* meta)
+{
+ if (data)
+ {
+ delete[] data;
+ data = nullptr;
+ }
+
+ FILE* f = fopen(filename, "rb");
+ if (!f)
+ return false;
+
+ fileName = filename;
+ this->meta = meta;
+ uint32 header;
+ if (fread(&header, 4, 1, f) != 1) // Signature
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(header);
+
+ if (header != 0x35424457)
+ {
+ fclose(f);
+ return false; //'WDB5'
+ }
+
+ 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(&layoutHash, 4, 1, f) != 1) // Layout hash
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(layoutHash);
+
+ if (layoutHash != meta->LayoutHash)
+ {
+ fclose(f);
+ return false;
+ }
+
+ 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);
+
+ fields = new FieldEntry[fieldCount];
+ if (fread(fields, fieldCount * sizeof(FieldEntry), 1, f) != 1)
+ {
+ fclose(f);
+ return false;
+ }
+
+ 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;
+ delete[] fields;
+}
+
+static char const* const nullStr = "";
+
+char* DB2SparseFileLoader::AutoProduceData(IndexTable const& indexTable, uint32 locale, std::vector<char*>& stringPool)
+{
+ typedef char* ptr;
+ if (meta->FieldCount != fieldCount)
+ return NULL;
+
+ //get struct size and index pos
+ uint32 recordsize = meta->GetRecordSize();
+
+ 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 = meta->GetStringFieldCount(false);
+ std::size_t localizedStringFields = meta->GetStringFieldCount(true);
+
+ // each string field at load have array of string for each locale
+ std::size_t stringHoldersRecordPoolSize = localizedStringFields * sizeof(LocalizedString) + (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 - (!meta->HasIndexFieldInData() ? 4 : 0)) - stringFields * sizeof(char*))];
+ memset(stringTable, 0, expandedDataSize - records * ((recordsize - (!meta->HasIndexFieldInData() ? 4 : 0)) - 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;
+
+ if (!meta->HasIndexFieldInData())
+ {
+ *((uint32*)(&dataTable[offset])) = y + minIndex;
+ offset += 4;
+ }
+
+ for (uint32 x = 0; x < fieldCount; ++x)
+ {
+ uint16 fieldBytes = 4 - fields[x].UnusedBits / 8;
+ for (uint32 z = 0; z < meta->ArraySizes[x]; ++z)
+ {
+ switch (meta->Types[x])
+ {
+ case FT_FLOAT:
+ {
+ float val = *reinterpret_cast<float*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]);
+ EndianConvert(val);
+ *((float*)(&dataTable[offset])) = val;
+ offset += 4;
+ fieldOffset += 4;
+ break;
+ }
+ case FT_INT:
+ {
+ ASSERT(fieldBytes && fieldBytes <= 4);
+ uint32 val;
+ switch (fieldBytes)
+ {
+ case 1:
+ val = *reinterpret_cast<uint8*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]);
+ break;
+ case 2:
+ {
+ uint16 val16 = *reinterpret_cast<uint16*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]);
+ EndianConvert(val16);
+ val = val16;
+ break;
+ }
+ case 3:
+ {
+#pragma pack(push, 1)
+ struct dbcint24 { uint8 v[3]; };
+#pragma pack(pop)
+ dbcint24 i24v = *reinterpret_cast<dbcint24*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]);
+ EndianConvert(i24v);
+ val = uint32(i24v.v[0]) | (uint32(i24v.v[1]) << 8) | (uint32(i24v.v[2]) << 16);
+ break;
+ }
+ case 4:
+ val = *reinterpret_cast<uint32*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]);
+ EndianConvert(val);
+ break;
+ default:
+ break;
+ }
+ *((uint32*)(&dataTable[offset])) = val;
+ offset += 4;
+ fieldOffset += fieldBytes;
+ break;
+ }
+ case FT_BYTE:
+ {
+ ASSERT(fieldBytes == 1);
+ *((uint8*)(&dataTable[offset])) = *reinterpret_cast<uint8*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]);
+ offset += 1;
+ fieldOffset += 1;
+ break;
+ }
+ case FT_SHORT:
+ {
+ ASSERT(fieldBytes == 2);
+ uint16 val = *reinterpret_cast<uint16*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]);
+ EndianConvert(val);
+ *((uint16*)(&dataTable[offset])) = val;
+ 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 += sizeof(LocalizedString);
+ 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 += sizeof(char*);
+ offset += sizeof(char*);
+ break;
+ }
+ default:
+ ASSERT(false, "Unknown format character '%c' found in %s meta", meta->Types[x], fileName);
+ break;
+ }
+ }
+ }
+
+ ++recordNum;
+ }
+
+ return dataTable;
+}
+
+char* DB2SparseFileLoader::AutoProduceStrings(char* dataTable, uint32 locale)
+{
+ if (meta->FieldCount != 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 = meta->GetRecordSize();
+ std::size_t stringFields = meta->GetStringFieldCount(true);
+ char* stringTable = new char[offsetsPos - dataStart - records * ((recordsize - (!meta->HasIndexFieldInData() ? 4 : 0)) - stringFields * sizeof(char*))];
+ memset(stringTable, 0, offsetsPos - dataStart - records * ((recordsize - (!meta->HasIndexFieldInData() ? 4 : 0)) - stringFields * sizeof(char*)));
+ char* stringPtr = stringTable;
+
+ uint32 offset = 0;
+
+ for (uint32 y = 0; y < offsetCount; y++)
+ {
+ if (!offsets[y].FileOffset || !offsets[y].RecordSize)
+ continue;
+
+ if (!meta->HasIndexFieldInData())
+ offset += 4;
+
+ uint32 fieldOffset = 0;
+ for (uint32 x = 0; x < fieldCount; ++x)
+ {
+ for (uint32 z = 0; z < meta->ArraySizes[x]; ++z)
+ {
+ switch (meta->Types[x])
+ {
+ case FT_FLOAT:
+ offset += 4;
+ fieldOffset += 4;
+ break;
+ case FT_INT:
+ offset += 4;
+ fieldOffset += 4 - fields[x].UnusedBits / 8;
+ break;
+ case FT_BYTE:
+ offset += 1;
+ fieldOffset += 1;
+ break;
+ case FT_SHORT:
+ offset += 2;
+ fieldOffset += 2;
+ break;
+ case FT_STRING:
+ {
+ 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:
+ {
+ fieldOffset += strlen((char*)&data[offsets[y].FileOffset - dataStart + fieldOffset]) + 1;
+ offset += sizeof(char*);
+ break;
+ }
+ default:
+ ASSERT(false, "Unknown format character '%c' found in %s meta", meta->Types[x], fileName);
+ break;
+ }
+ }
+ }
+ }
+
+ return stringTable;
+}
+
+char* DB2SparseDatabaseLoader::Load(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;
+
+ if (_meta->GetDbFieldCount() != result->GetFieldCount())
+ return nullptr;
+
+ // get struct size and index pos
+ uint32 indexField = _meta->GetDbIndexField();
+ uint32 recordSize = _meta->GetRecordSize();
+
+ // we store flat holders pool as single memory block
+ std::size_t stringFields = _meta->GetStringFieldCount(false);
+ std::size_t localizedStringFields = _meta->GetStringFieldCount(true);
+
+ // each string field at load have array of string for each locale
+ std::size_t stringHoldersRecordPoolSize = localizedStringFields * sizeof(LocalizedString) + (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[indexField].GetUInt32();
+
+ // Attempt to overwrite existing data
+ char* dataValue = indexTable.Get(indexValue);
+ if (!dataValue)
+ {
+ newIndexes[newRecords] = indexValue;
+ dataValue = &tempDataTable[newRecords++ * recordSize];
+ }
+
+ uint32 f = 0;
+ if (!_meta->HasIndexFieldInData())
+ {
+ *((uint32*)(&dataValue[offset])) = indexValue;
+ offset += 4;
+ ++f;
+ }
+
+ for (uint32 x = 0; x < _meta->FieldCount; ++x)
+ {
+ for (uint32 z = 0; z < _meta->ArraySizes[x]; ++z)
+ {
+ switch (_meta->Types[x])
+ {
+ case FT_FLOAT:
+ *((float*)(&dataValue[offset])) = fields[f].GetFloat();
+ offset += 4;
+ break;
+ 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_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 += sizeof(LocalizedString);
+ 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 += sizeof(char*);
+ offset += sizeof(char*);
+ break;
+ }
+ default:
+ ASSERT(false, "Unknown format character '%c' found in %s meta", _meta->Types[x], _storageName.c_str());
+ break;
+ }
+ ++f;
+ }
+ }
+
+ 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(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 = _meta->GetStringFieldCount(true);
+ if (result->GetFieldCount() != stringFields + 1 /*ID*/)
+ return;
+
+ uint32 fieldCount = _meta->FieldCount;
+ uint32 recordSize = _meta->GetRecordSize();
+
+ 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))
+ {
+ if (!_meta->HasIndexFieldInData())
+ offset += 4;
+
+ for (uint32 x = 0; x < fieldCount; ++x)
+ {
+ for (uint32 z = 0; z < _meta->ArraySizes[x]; ++z)
+ {
+ switch (_meta->Types[x])
+ {
+ case FT_FLOAT:
+ case FT_INT:
+ offset += 4;
+ break;
+ case FT_BYTE:
+ offset += 1;
+ 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;
+ }
+ default:
+ ASSERT(false, "Unknown format character '%c' found in %s meta", _meta->Types[x], _storageName.c_str());
+ 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..0936947ea6a
--- /dev/null
+++ b/src/server/shared/DataStores/DB2SparseStorageLoader.h
@@ -0,0 +1,123 @@
+/*
+ * 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 "DB2Meta.h"
+#include "Utilities/ByteConverter.h"
+#include "Implementation/HotfixDatabase.h"
+#include <unordered_map>
+#include <vector>
+
+class TC_SHARED_API 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 TC_SHARED_API DB2SparseFileLoader
+{
+ public:
+ DB2SparseFileLoader();
+ ~DB2SparseFileLoader();
+
+ bool Load(char const* filename, DB2Meta const* meta);
+
+ uint32 GetNumRows() const { return recordCount; }
+ uint32 GetCols() const { return fieldCount; }
+ uint32 GetTableHash() const { return tableHash; }
+ uint32 GetLayoutHash() const { return layoutHash; }
+ bool IsLoaded() const { return (data != NULL); }
+ char* AutoProduceData(IndexTable const& indexTable, uint32 locale, std::vector<char*>& stringPool);
+ char* AutoProduceStrings(char* dataTable, uint32 locale);
+
+private:
+#pragma pack(push, 1)
+ struct OffsetTableEntry
+ {
+ uint32 FileOffset;
+ uint16 RecordSize;
+ };
+ struct FieldEntry
+ {
+ uint16 UnusedBits;
+ uint16 Offset;
+ };
+#pragma pack(pop)
+
+ char const* fileName;
+ DB2Meta const* meta;
+
+ // WDB2 / WCH2 fields
+ uint32 recordSize;
+ uint32 recordCount;
+ uint32 fieldCount;
+ uint32 offsetsPos;
+ uint32 tableHash;
+ uint32 layoutHash;
+ uint32 minIndex;
+ uint32 maxIndex;
+ uint32 localeMask;
+ uint32 copyIdSize;
+ uint32 metaFlags;
+ FieldEntry* fields;
+
+ uint32 dataStart;
+ unsigned char* data;
+ OffsetTableEntry* offsets;
+};
+
+class TC_SHARED_API DB2SparseDatabaseLoader
+{
+public:
+ DB2SparseDatabaseLoader(std::string const& storageName, DB2Meta const* meta) : _storageName(storageName), _meta(meta) { }
+
+ char* Load(HotfixDatabaseStatements preparedStatement, IndexTable const& indexTable, std::vector<char*>& stringPool);
+ void LoadStrings(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;
+ DB2Meta const* _meta;
+};
+
+#endif
diff --git a/src/server/shared/DataStores/DB2StorageLoader.cpp b/src/server/shared/DataStores/DB2StorageLoader.cpp
index a1acd3b5eac..fd3e0a257cd 100644
--- a/src/server/shared/DataStores/DB2StorageLoader.cpp
+++ b/src/server/shared/DataStores/DB2StorageLoader.cpp
@@ -23,25 +23,28 @@
DB2FileLoader::DB2FileLoader()
{
fileName = nullptr;
+ meta = nullptr;
+
recordSize = 0;
recordCount = 0;
fieldCount = 0;
stringSize = 0;
- fieldsOffset = nullptr;
- data = nullptr;
- stringTable = nullptr;
-
tableHash = 0;
- build = 0;
-
- unk1 = 0;
+ layoutHash = 0;
minIndex = 0;
maxIndex = 0;
localeMask = 0;
- unk5 = 0;
+ copyIdSize = 0;
+
+ data = nullptr;
+ stringTable = nullptr;
+ idTable = nullptr;
+ idTableSize = 0;
+ copyTable = nullptr;
+ fields = nullptr;
}
-bool DB2FileLoader::Load(const char *filename, const char *fmt)
+bool DB2FileLoader::Load(char const* filename, DB2Meta const* meta)
{
if (data)
{
@@ -54,8 +57,9 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
return false;
fileName = filename;
+ this->meta = meta;
uint32 header;
- if (fread(&header, 4, 1, f) != 1) // Signature
+ if (fread(&header, 4, 1, f) != 1) // Signature
{
fclose(f);
return false;
@@ -63,13 +67,13 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
EndianConvert(header);
- if (header != 0x32424457)
+ if (header != 0x35424457)
{
fclose(f);
- return false; //'WDB2'
+ return false; //'WDB5'
}
- 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 +81,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 +89,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 +97,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 +105,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,23 +113,21 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
EndianConvert(tableHash);
- if (fread(&build, 4, 1, f) != 1) // Build
+ if (fread(&layoutHash, 4, 1, f) != 1) // Build
{
fclose(f);
return false;
}
- EndianConvert(build);
-
- if (fread(&unk1, 4, 1, f) != 1) // Unknown WDB2
+ if (layoutHash != meta->LayoutHash)
{
fclose(f);
return false;
}
- EndianConvert(unk1);
+ EndianConvert(layoutHash);
- if (fread(&minIndex, 4, 1, f) != 1) // MinIndex WDB2
+ if (fread(&minIndex, 4, 1, f) != 1) // MinIndex WDB2
{
fclose(f);
return false;
@@ -134,7 +135,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 +143,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,33 +151,34 @@ 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;
}
- fieldsOffset = new uint32[fieldCount];
- fieldsOffset[0] = 0;
- for (uint32 i = 1; i < fieldCount; i++)
- {
- fieldsOffset[i] = fieldsOffset[i - 1];
- if (fmt[i - 1] == FT_BYTE) // byte fields
- fieldsOffset[i] += 1;
- else if (fmt[i - 1] == FT_LONG)
- fieldsOffset[i] += 8;
- else // 4 byte fields (int32/float/strings)
- fieldsOffset[i] += 4;
+ EndianConvert(metaFlags);
+
+ ASSERT((meta->IndexField == -1) || (meta->IndexField == (metaFlags >> 16)));
+
+ fields = new FieldEntry[fieldCount];
+ if (fread(fields, fieldCount * sizeof(FieldEntry), 1, f) != 1)
+ {
+ fclose(f);
+ return false;
}
+ if (!meta->HasIndexFieldInData())
+ idTableSize = recordCount * sizeof(uint32);
+
data = new unsigned char[recordSize * recordCount + stringSize];
stringTable = data + recordSize * recordCount;
@@ -186,151 +188,135 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
return false;
}
- fclose(f);
- return true;
-}
-
-DB2FileLoader::~DB2FileLoader()
-{
- if (data)
- delete [] data;
- if (fieldsOffset)
- delete [] fieldsOffset;
-}
-
-DB2FileLoader::Record DB2FileLoader::getRecord(size_t id)
-{
- assert(data);
- 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)
+ if (idTableSize)
{
- switch (format[x])
+ idTable = new unsigned char[idTableSize];
+ if (fread(idTable, idTableSize, 1, f) != 1)
{
- case FT_FLOAT:
- case FT_INT:
- recordsize += 4;
- break;
- case FT_STRING:
- case FT_STRING_NOT_LOCALIZED:
- recordsize += sizeof(char*);
- break;
- case FT_SORT:
- i = x;
- break;
- case FT_IND:
- i = x;
- recordsize += 4;
- break;
- case FT_BYTE:
- recordsize += 1;
- break;
- case FT_LONG:
- recordsize += 8;
- break;
+ fclose(f);
+ return false;
}
}
- if (index_pos)
- *index_pos = i;
+ if (copyIdSize)
+ {
+ copyTable = new unsigned char[copyIdSize];
+ if (fread(copyTable, copyIdSize, 1, f) != 1)
+ {
+ fclose(f);
+ return false;
+ }
+ }
- return recordsize;
+ fclose(f);
+ return true;
}
-uint32 DB2FileLoader::GetFormatStringFieldCount(const char* format)
+DB2FileLoader::~DB2FileLoader()
{
- uint32 stringfields = 0;
- for (uint32 x = 0; format[x]; ++x)
- if (format[x] == FT_STRING || format[x] == FT_STRING_NOT_LOCALIZED)
- ++stringfields;
-
- return stringfields;
+ delete[] data;
+ delete[] idTable;
+ delete[] copyTable;
+ delete[] fields;
}
-uint32 DB2FileLoader::GetFormatLocalizedStringFieldCount(char const* format)
+DB2FileLoader::Record DB2FileLoader::getRecord(size_t id)
{
- uint32 stringfields = 0;
- for (uint32 x = 0; format[x]; ++x)
- if (format[x] == FT_STRING)
- ++stringfields;
-
- return stringfields;
+ assert(data);
+ return Record(*this, data + id * recordSize);
}
-char* DB2FileLoader::AutoProduceData(const char* format, uint32& records, char**& indexTable)
+char* DB2FileLoader::AutoProduceData(uint32& records, char**& indexTable)
{
- typedef char * ptr;
- if (strlen(format) != fieldCount)
+ typedef char* ptr;
+ if (meta->FieldCount != fieldCount)
return NULL;
//get struct size and index pos
- int32 indexField;
- uint32 recordsize = GetFormatRecordSize(format, &indexField);
+ uint32 indexField = meta->GetIndexField();
+ uint32 recordsize = meta->GetRecordSize();
- if (indexField >= 0)
+ uint32 maxi = 0;
+ //find max index
+ if (!idTableSize)
{
- uint32 maxi = 0;
- //find max index
- for (uint32 y = 0; y < recordCount; y++)
+ for (uint32 y = 0; y < recordCount; ++y)
{
- uint32 ind = getRecord(y).getUInt(indexField);
+ uint32 ind = getRecord(y).getUInt(indexField, 0);
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];
+ for (uint32 y = 0; y < recordCount; ++y)
+ {
+ uint32 ind = ((uint32*)idTable)[y];
+ if (ind > maxi)
+ maxi = ind;
+ }
}
- char* dataTable = new char[recordCount * recordsize];
+ for (uint32 y = 0; y < copyIdSize; y += 8)
+ {
+ uint32 ind = *((uint32*)(copyTable + y));
+ if (ind > maxi)
+ maxi = ind;
+ }
+
+ ++maxi;
+ records = maxi;
+ indexTable = new ptr[maxi];
+ memset(indexTable, 0, maxi * sizeof(ptr));
+
+ char* dataTable = new char[(recordCount + (copyIdSize / 8)) * recordsize];
uint32 offset = 0;
for (uint32 y = 0; y < recordCount; y++)
{
- if (indexField >= 0)
- indexTable[getRecord(y).getUInt(indexField)] = &dataTable[offset];
- else
- indexTable[y] = &dataTable[offset];
+ uint32 indexVal = meta->HasIndexFieldInData() ? getRecord(y).getUInt(indexField, 0) : ((uint32*)idTable)[y];
+
+ indexTable[indexVal] = &dataTable[offset];
- for (uint32 x = 0; x < fieldCount; x++)
+ if (!meta->HasIndexFieldInData())
{
- switch (format[x])
+ *((uint32*)(&dataTable[offset])) = indexVal;
+ offset += 4;
+ }
+
+ Record rec = getRecord(y);
+ for (uint32 x = 0; x < fieldCount; ++x)
+ {
+ for (uint32 z = 0; z < meta->ArraySizes[x]; ++z)
{
- 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_LONG:
- *((uint64*)(&dataTable[offset])) = getRecord(y).getUInt64(x);
- offset += 8;
- break;
- case FT_STRING:
- case FT_STRING_NOT_LOCALIZED:
- *((char**)(&dataTable[offset])) = nullptr; // will be replaces non-empty or "" strings in AutoProduceStrings
- offset += sizeof(char*);
- break;
+ switch (meta->Types[x])
+ {
+ case FT_FLOAT:
+ *((float*)(&dataTable[offset])) = rec.getFloat(x, z);
+ offset += 4;
+ break;
+ case FT_INT:
+ *((uint32*)(&dataTable[offset])) = rec.getUInt(x, z);
+ offset += 4;
+ break;
+ case FT_BYTE:
+ *((uint8*)(&dataTable[offset])) = rec.getUInt8(x, z);
+ offset += 1;
+ break;
+ case FT_SHORT:
+ *((uint16*)(&dataTable[offset])) = rec.getUInt16(x, z);
+ offset += 2;
+ break;
+ case FT_STRING:
+ case FT_STRING_NOT_LOCALIZED:
+ *((char**)(&dataTable[offset])) = nullptr; // will be replaced by non-empty or "" strings in AutoProduceStrings
+ offset += sizeof(char*);
+ break;
+ default:
+ ASSERT(false, "Unknown format character '%c' found in %s meta", meta->Types[x], fileName);
+ break;
+ }
}
}
}
@@ -340,17 +326,17 @@ char* DB2FileLoader::AutoProduceData(const char* format, uint32& records, char**
static char const* const nullStr = "";
-char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* dataTable)
+char* DB2FileLoader::AutoProduceStringsArrayHolders(char* dataTable)
{
- if (strlen(format) != fieldCount)
+ if (meta->FieldCount != fieldCount)
return nullptr;
// we store flat holders pool as single memory block
- std::size_t stringFields = GetFormatStringFieldCount(format);
+ std::size_t stringFields = meta->GetStringFieldCount(false);
if (!stringFields)
return nullptr;
- std::size_t localizedStringFields = GetFormatLocalizedStringFieldCount(format);
+ std::size_t localizedStringFields = meta->GetStringFieldCount(true);
// each string field at load have array of string for each locale
std::size_t stringHoldersRecordPoolSize = localizedStringFields * sizeof(LocalizedString) + (stringFields - localizedStringFields) * sizeof(char*);
@@ -369,37 +355,43 @@ char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* da
{
uint32 stringFieldOffset = 0;
- for (uint32 x = 0; x < fieldCount; x++)
+ if (!meta->HasIndexFieldInData())
+ offset += 4;
+
+ for (uint32 x = 0; x < fieldCount; ++x)
{
- switch (format[x])
+ for (uint32 z = 0; z < meta->ArraySizes[x]; ++z)
{
- 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_STRING:
- case FT_STRING_NOT_LOCALIZED:
+ switch (meta->Types[x])
{
- // init db2 string field slots by pointers to string holders
- char const*** slot = (char const***)(&dataTable[offset]);
- *slot = (char const**)(&stringHoldersPool[stringHoldersRecordPoolSize * y + stringFieldOffset]);
- if (format[x] == FT_STRING)
- stringFieldOffset += sizeof(LocalizedString);
- else
- stringFieldOffset += sizeof(char*);
+ case FT_FLOAT:
+ case FT_INT:
+ offset += 4;
+ break;
+ case FT_BYTE:
+ offset += 1;
+ break;
+ case FT_SHORT:
+ offset += 2;
+ break;
+ case FT_STRING:
+ case FT_STRING_NOT_LOCALIZED:
+ {
+ // init db2 string field slots by pointers to string holders
+ char const*** slot = (char const***)(&dataTable[offset]);
+ *slot = (char const**)(&stringHoldersPool[stringHoldersRecordPoolSize * y + stringFieldOffset]);
+ if (meta->Types[x] == FT_STRING)
+ stringFieldOffset += sizeof(LocalizedString);
+ else
+ stringFieldOffset += sizeof(char*);
- offset += sizeof(char*);
- break;
+ offset += sizeof(char*);
+ break;
+ }
+ default:
+ ASSERT(false, "Unknown format character '%c' found in %s meta", meta->Types[x], fileName);
+ break;
}
- default:
- ASSERT(false, "unknown format character %c", format[x]);
}
}
}
@@ -408,9 +400,9 @@ char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* da
return stringHoldersPool;
}
-char* DB2FileLoader::AutoProduceStrings(const char* format, char* dataTable, uint32 locale)
+char* DB2FileLoader::AutoProduceStrings(char* dataTable, uint32 locale)
{
- if (strlen(format) != fieldCount)
+ if (meta->FieldCount != fieldCount)
return nullptr;
if (!(localeMask & (1 << locale)))
@@ -437,41 +429,49 @@ char* DB2FileLoader::AutoProduceStrings(const char* format, char* dataTable, uin
for (uint32 y = 0; y < recordCount; y++)
{
- for (uint32 x = 0; x < fieldCount; x++)
+ if (!meta->HasIndexFieldInData())
+ offset += 4;
+
+ for (uint32 x = 0; x < fieldCount; ++x)
{
- switch (format[x])
+ for (uint32 z = 0; z < meta->ArraySizes[x]; ++z)
{
- 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_STRING:
+ switch (meta->Types[x])
{
- // fill only not filled entries
- LocalizedString* db2str = *(LocalizedString**)(&dataTable[offset]);
- if (db2str->Str[locale] == nullStr)
+ case FT_FLOAT:
+ case FT_INT:
+ offset += 4;
+ break;
+ case FT_BYTE:
+ offset += 1;
+ break;
+ case FT_SHORT:
+ offset += 2;
+ break;
+ case FT_STRING:
{
- char const* st = getRecord(y).getString(x);
- db2str->Str[locale] = stringPool + (st - (char const*)stringTable);
- }
+ // fill only not filled entries
+ LocalizedString* db2str = *(LocalizedString**)(&dataTable[offset]);
+ if (db2str->Str[locale] == nullStr)
+ {
+ char const* st = getRecord(y).getString(x, z);
+ db2str->Str[locale] = stringPool + (st - (char const*)stringTable);
+ }
- offset += sizeof(char*);
- break;
- }
- case FT_STRING_NOT_LOCALIZED:
- {
- char** db2str = (char**)(&dataTable[offset]);
- char const* st = getRecord(y).getString(x);
- *db2str = stringPool + (st - (char const*)stringTable);
- offset += sizeof(char*);
- break;
+ offset += sizeof(char*);
+ break;
+ }
+ case FT_STRING_NOT_LOCALIZED:
+ {
+ char** db2str = (char**)(&dataTable[offset]);
+ char const* st = getRecord(y).getString(x, z);
+ *db2str = stringPool + (st - (char const*)stringTable);
+ offset += sizeof(char*);
+ break;
+ }
+ default:
+ ASSERT(false, "Unknown format character '%c' found in %s meta", meta->Types[x], fileName);
+ break;
}
}
}
@@ -480,24 +480,48 @@ 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)
+void DB2FileLoader::AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable)
+{
+ uint32 recordsize = meta->GetRecordSize();
+ uint32 offset = recordCount * recordsize;
+ 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);
+
+ if (meta->HasIndexFieldInData())
+ *((uint32*)(&dataTable[offset + fields[meta->GetIndexField()].Offset])) = to;
+ else
+ *((uint32*)(&dataTable[offset])) = to;
+
+ offset += recordsize;
+ }
+ }
+}
+
+char* DB2DatabaseLoader::Load(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));
if (!result)
return nullptr;
- uint32 const fieldCount = strlen(format);
- if (fieldCount != result->GetFieldCount())
+ if (_meta->GetDbFieldCount() != result->GetFieldCount())
return nullptr;
// get struct size and index pos
- int32 indexField;
- uint32 recordSize = DB2FileLoader::GetFormatRecordSize(format, &indexField);
+ uint32 indexField = _meta->GetDbIndexField();
+ uint32 recordSize = _meta->GetRecordSize();
// we store flat holders pool as single memory block
- std::size_t stringFields = DB2FileLoader::GetFormatStringFieldCount(format);
- std::size_t localizedStringFields = DB2FileLoader::GetFormatLocalizedStringFieldCount(format);
+ std::size_t stringFields = _meta->GetStringFieldCount(false);
+ std::size_t localizedStringFields = _meta->GetStringFieldCount(true);
// each string field at load have array of string for each locale
std::size_t stringHoldersRecordPoolSize = localizedStringFields * sizeof(LocalizedString) + (stringFields - localizedStringFields) * sizeof(char*);
@@ -516,15 +540,9 @@ char* DB2DatabaseLoader::Load(const char* format, HotfixDatabaseStatements prepa
// Resize index table
// database query *MUST* contain ORDER BY `index_field` DESC clause
- uint32 indexTableSize;
- if (indexField >= 0)
- {
- indexTableSize = (*result)[indexField].GetUInt32() + 1;
- if (indexTableSize < records)
- indexTableSize = records;
- }
- else
- indexTableSize = records + result->GetRowCount();
+ uint32 indexTableSize = (*result)[indexField].GetUInt32() + 1;
+ if (indexTableSize < records)
+ indexTableSize = records;
if (indexTableSize > records)
{
@@ -546,11 +564,7 @@ char* DB2DatabaseLoader::Load(const char* format, HotfixDatabaseStatements prepa
uint32 offset = 0;
uint32 stringFieldOffset = 0;
- uint32 indexValue;
- if (indexField >= 0)
- indexValue = fields[indexField].GetUInt32();
- else
- indexValue = records + rec;
+ uint32 indexValue = fields[indexField].GetUInt32();
// Attempt to overwrite existing data
char* dataValue = indexTable[indexValue];
@@ -560,55 +574,69 @@ char* DB2DatabaseLoader::Load(const char* format, HotfixDatabaseStatements prepa
dataValue = &tempDataTable[newRecords++ * recordSize];
}
- for (uint32 f = 0; f < fieldCount; f++)
+ uint32 f = 0;
+ if (!_meta->HasIndexFieldInData())
{
- switch (format[f])
+ *((uint32*)(&dataValue[offset])) = indexValue;
+ offset += 4;
+ ++f;
+ }
+
+ for (uint32 x = 0; x < _meta->FieldCount; ++x)
+ {
+ for (uint32 z = 0; z < _meta->ArraySizes[x]; ++z)
{
- 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_STRING:
+ switch (_meta->Types[x])
{
- LocalizedString** slot = (LocalizedString**)(&dataValue[offset]);
- *slot = (LocalizedString*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringFieldOffset]);
- ASSERT(*slot);
+ case FT_FLOAT:
+ *((float*)(&dataValue[offset])) = fields[f].GetFloat();
+ offset += 4;
+ break;
+ 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_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);
+ // 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 += sizeof(LocalizedString);
- offset += sizeof(char*);
- break;
- }
- case FT_STRING_NOT_LOCALIZED:
- {
- char const** slot = (char const**)(&dataValue[offset]);
- *slot = (char*)(&stringHolders[stringHoldersRecordPoolSize * rec + sizeof(LocalizedString) * stringFieldOffset]);
- ASSERT(*slot);
+ stringFieldOffset += sizeof(LocalizedString);
+ 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);
+ // 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 += sizeof(char*);
- offset += sizeof(char*);
- break;
+ stringFieldOffset += sizeof(char*);
+ offset += sizeof(char*);
+ break;
+ }
+ default:
+ ASSERT(false, "Unknown format character '%c' found in %s meta", _meta->Types[x], _storageName.c_str());
+ break;
}
+ ++f;
}
}
@@ -639,7 +667,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(HotfixDatabaseStatements preparedStatement, uint32 locale, uint32 records, char** indexTable, std::vector<char*>& stringPool)
{
PreparedStatement* stmt = HotfixDatabase.GetPreparedStatement(preparedStatement);
stmt->setString(0, localeNames[locale]);
@@ -647,14 +675,12 @@ void DB2DatabaseLoader::LoadStrings(const char* format, HotfixDatabaseStatements
if (!result)
return;
- size_t stringFields = DB2FileLoader::GetFormatLocalizedStringFieldCount(format);
+ std::size_t stringFields = _meta->GetStringFieldCount(true);
if (result->GetFieldCount() != stringFields + 1 /*ID*/)
return;
- uint32 const fieldCount = strlen(format);
- int32 indexField;
- uint32 recordSize = DB2FileLoader::GetFormatRecordSize(format, &indexField);
- ASSERT(indexField >= 0, "DB2Storage must be indexed to load localized strings");
+ uint32 fieldCount = _meta->FieldCount;
+ uint32 recordSize = _meta->GetRecordSize();
do
{
@@ -663,35 +689,49 @@ void DB2DatabaseLoader::LoadStrings(const char* format, HotfixDatabaseStatements
uint32 stringFieldNumInRecord = 0;
uint32 indexValue = fields[0].GetUInt32();
+ if (indexValue >= records)
+ continue;
+
// Attempt to overwrite existing data
if (char* dataValue = indexTable[indexValue])
{
- for (uint32 x = 0; x < fieldCount; x++)
+ if (!_meta->HasIndexFieldInData())
+ offset += 4;
+
+ for (uint32 x = 0; x < fieldCount; ++x)
{
- switch (format[x])
+ for (uint32 z = 0; z < _meta->ArraySizes[x]; ++z)
{
- 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_STRING:
+ switch (_meta->Types[x])
{
- // 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;
+ case FT_FLOAT:
+ case FT_INT:
+ offset += 4;
+ break;
+ case FT_BYTE:
+ offset += 1;
+ 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(LocalizedString*);
+ break;
+ }
+ case FT_STRING_NOT_LOCALIZED:
+ offset += sizeof(char*);
+ break;
+ default:
+ ASSERT(false, "Unknown format character '%c' found in %s meta", _meta->Types[x], _storageName.c_str());
+ break;
}
}
}
@@ -699,7 +739,7 @@ void DB2DatabaseLoader::LoadStrings(const char* format, HotfixDatabaseStatements
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);
+ TC_LOG_ERROR("sql.sql", "Hotfix locale table for storage %s references row that does not exist %u locale %s!", _storageName.c_str(), indexValue, localeNames[locale]);
} while (result->NextRow());
diff --git a/src/server/shared/DataStores/DB2StorageLoader.h b/src/server/shared/DataStores/DB2StorageLoader.h
index 41705c67f19..b302a1afe7d 100644
--- a/src/server/shared/DataStores/DB2StorageLoader.h
+++ b/src/server/shared/DataStores/DB2StorageLoader.h
@@ -18,11 +18,11 @@
#ifndef DB2_FILE_LOADER_H
#define DB2_FILE_LOADER_H
-#include "Define.h"
+#include "DB2Meta.h"
#include "Utilities/ByteConverter.h"
#include "Implementation/HotfixDatabase.h"
-#include <cassert>
-#include <list>
+#include "Errors.h"
+#include <vector>
class TC_SHARED_API DB2FileLoader
{
@@ -30,46 +30,101 @@ class TC_SHARED_API DB2FileLoader
DB2FileLoader();
~DB2FileLoader();
- bool Load(const char *filename, const char *fmt);
+ bool Load(char const* filename, DB2Meta const* meta);
class Record
{
public:
- float getFloat(size_t field) const
+ float getFloat(uint32 field, uint32 arrayIndex) const
{
- assert(field < file.fieldCount);
- float val = *reinterpret_cast<float*>(offset + file.GetOffset(field));
+ ASSERT(field < file.fieldCount);
+ float val = *reinterpret_cast<float*>(offset + GetOffset(field) + arrayIndex * sizeof(float));
EndianConvert(val);
return val;
}
- uint32 getUInt(size_t field) const
+
+ uint32 getUInt(uint32 field, uint32 arrayIndex) const
{
- assert(field < file.fieldCount);
- uint32 val = *reinterpret_cast<uint32*>(offset + file.GetOffset(field));
- EndianConvert(val);
- return val;
+ ASSERT(field < file.fieldCount);
+ return GetVarInt(field, GetByteSize(field), arrayIndex);
}
- uint8 getUInt8(size_t field) const
+
+ uint8 getUInt8(uint32 field, uint32 arrayIndex) const
{
- assert(field < file.fieldCount);
- return *reinterpret_cast<uint8*>(offset + file.GetOffset(field));
+ ASSERT(field < file.fieldCount);
+ ASSERT(GetByteSize(field) == 1);
+ return *reinterpret_cast<uint8*>(offset + GetOffset(field) + arrayIndex * sizeof(uint8));
}
- uint64 getUInt64(size_t field) const
+
+ uint16 getUInt16(uint32 field, uint32 arrayIndex) const
{
- assert(field < file.fieldCount);
- uint64 val = *reinterpret_cast<uint64*>(offset + file.GetOffset(field));
+ ASSERT(field < file.fieldCount);
+ ASSERT(GetByteSize(field) == 2);
+ uint16 val = *reinterpret_cast<uint16*>(offset + GetOffset(field) + arrayIndex * sizeof(uint16));
EndianConvert(val);
return val;
}
- const char *getString(size_t field) const
+
+ char const* getString(uint32 field, uint32 arrayIndex) const
{
- assert(field < file.fieldCount);
- size_t stringOffset = getUInt(field);
- assert(stringOffset < file.stringSize);
+ ASSERT(field < file.fieldCount);
+ uint32 stringOffset = *reinterpret_cast<uint32*>(offset + GetOffset(field) + arrayIndex * sizeof(uint32));
+ EndianConvert(stringOffset);
+ ASSERT(stringOffset < file.stringSize);
return reinterpret_cast<char*>(file.stringTable + stringOffset);
}
private:
+ uint16 GetOffset(uint32 field) const
+ {
+ ASSERT(field < file.fieldCount);
+ return file.fields[field].Offset;
+ }
+
+ uint16 GetByteSize(uint32 field) const
+ {
+ ASSERT(field < file.fieldCount);
+ return 4 - file.fields[field].UnusedBits / 8;
+ }
+
+ uint32 GetVarInt(uint32 field, uint16 size, uint32 arrayIndex) const
+ {
+ ASSERT(field < file.fieldCount);
+ switch (size)
+ {
+ case 1:
+ {
+ return *reinterpret_cast<uint8*>(offset + GetOffset(field) + arrayIndex * sizeof(uint8));
+ }
+ case 2:
+ {
+ uint16 val = *reinterpret_cast<uint16*>(offset + GetOffset(field) + arrayIndex * sizeof(uint16));
+ EndianConvert(val);
+ return val;
+ }
+ case 3:
+ {
+#pragma pack(push, 1)
+ struct dbcint24 { uint8 v[3]; };
+#pragma pack(pop)
+ dbcint24 val = *reinterpret_cast<dbcint24*>(offset + GetOffset(field) + arrayIndex * sizeof(dbcint24));
+ EndianConvert(val);
+ return uint32(val.v[0]) | (uint32(val.v[1]) << 8) | (uint32(val.v[2]) << 16);
+ }
+ case 4:
+ {
+ uint32 val = *reinterpret_cast<uint32*>(offset + GetOffset(field) + arrayIndex * sizeof(uint32));
+ EndianConvert(val);
+ return val;
+ }
+ default:
+ break;
+ }
+
+ ASSERT(false, "GetByteSize(field) < 4");
+ return 0;
+ }
+
Record(DB2FileLoader &file_, unsigned char *offset_): offset(offset_), file(file_) {}
unsigned char *offset;
DB2FileLoader &file;
@@ -79,52 +134,62 @@ class TC_SHARED_API DB2FileLoader
// 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; }
- uint32 GetHash() const { return tableHash; }
+ uint32 GetTableHash() const { return tableHash; }
+ uint32 GetLayoutHash() const { return layoutHash; }
bool IsLoaded() const { return (data != NULL); }
- char* AutoProduceData(const char* fmt, uint32& count, char**& indexTable);
- char* AutoProduceStringsArrayHolders(const char* fmt, char* dataTable);
- char* AutoProduceStrings(const char* fmt, char* dataTable, uint32 locale);
- static uint32 GetFormatRecordSize(const char * format, int32 * index_pos = NULL);
- static uint32 GetFormatStringFieldCount(const char * format);
- static uint32 GetFormatLocalizedStringFieldCount(const char * format);
+ char* AutoProduceData(uint32& count, char**& indexTable);
+ char* AutoProduceStringsArrayHolders(char* dataTable);
+ char* AutoProduceStrings(char* dataTable, uint32 locale);
+ void AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable);
+
private:
+#pragma pack(push, 1)
+ struct FieldEntry
+ {
+ uint16 UnusedBits;
+ uint16 Offset;
+ };
+#pragma pack(pop)
+
char const* fileName;
+ DB2Meta const* meta;
+ // WDB2 / WCH2 fields
uint32 recordSize;
uint32 recordCount;
uint32 fieldCount;
uint32 stringSize;
- uint32 *fieldsOffset;
- unsigned char *data;
- unsigned char *stringTable;
-
- // 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 tableHash;
+ uint32 layoutHash;
+ uint32 minIndex;
+ uint32 maxIndex;
+ uint32 localeMask;
+ uint32 copyIdSize;
+ uint32 metaFlags;
+
+ unsigned char* data;
+ unsigned char* stringTable;
+ unsigned char* idTable;
+ uint32 idTableSize;
+ unsigned char* copyTable;
+ FieldEntry* fields;
};
class TC_SHARED_API DB2DatabaseLoader
{
public:
- explicit DB2DatabaseLoader(std::string const& storageName) : _storageName(storageName) { }
+ DB2DatabaseLoader(std::string const& storageName, DB2Meta const* meta) : _storageName(storageName), _meta(meta) { }
- 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(HotfixDatabaseStatements preparedStatement, uint32& records, char**& indexTable, char*& stringHolders, std::vector<char*>& stringPool);
+ void LoadStrings(HotfixDatabaseStatements preparedStatement, uint32 locale, uint32 records, char** indexTable, std::vector<char*>& stringPool);
static char* AddString(char const** holder, std::string const& value);
private:
std::string _storageName;
+ DB2Meta const* _meta;
};
#endif
diff --git a/src/server/shared/DataStores/DB2Store.h b/src/server/shared/DataStores/DB2Store.h
index 72271ce507b..bf10d78f37b 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,9 +28,20 @@
class DB2StorageBase
{
public:
- virtual ~DB2StorageBase() { }
+ DB2StorageBase(char const* fileName, DB2Meta const* meta, HotfixDatabaseStatements preparedStmtIndex)
+ : _tableHash(0), _layoutHash(0), _fileName(fileName), _fieldCount(0), _meta(meta), _dataTable(nullptr), _dataTableEx(nullptr), _hotfixStatement(preparedStmtIndex) { }
- uint32 GetHash() const { return _tableHash; }
+ virtual ~DB2StorageBase()
+ {
+ delete[] reinterpret_cast<char*>(_dataTable);
+ delete[] reinterpret_cast<char*>(_dataTableEx);
+ for (char* strings : _stringPool)
+ delete[] strings;
+ }
+
+ uint32 GetTableHash() const { return _tableHash; }
+
+ uint32 GetLayoutHash() const { return _layoutHash; }
virtual bool HasRecord(uint32 id) const = 0;
@@ -37,19 +49,87 @@ public:
virtual void EraseRecord(uint32 id) = 0;
+ std::string const& GetFileName() const { return _fileName; }
+
+ uint32 GetFieldCount() const { return _fieldCount; }
+
+ DB2Meta const* GetMeta() const { return _meta; }
+
+ 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;
+
protected:
+ void WriteRecordData(char const* entry, uint32 locale, ByteBuffer& buffer) const
+ {
+ if (!_meta->HasIndexFieldInData())
+ entry += 4;
+
+ for (uint32 i = 0; i < _meta->FieldCount; ++i)
+ {
+ for (uint32 a = 0; a < _meta->ArraySizes[i]; ++a)
+ {
+ switch (_meta->Types[i])
+ {
+ case FT_INT:
+ buffer << *(uint32*)entry;
+ entry += 4;
+ break;
+ case FT_FLOAT:
+ buffer << *(float*)entry;
+ entry += 4;
+ break;
+ case FT_BYTE:
+ buffer << *(uint8*)entry;
+ entry += 1;
+ break;
+ case FT_SHORT:
+ buffer << *(uint16*)entry;
+ entry += 2;
+ break;
+ case FT_STRING:
+ {
+ LocalizedString* locStr = *(LocalizedString**)entry;
+ if (locStr->Str[locale][0] == '\0')
+ locale = 0;
+
+ buffer << locStr->Str[locale];
+ entry += sizeof(LocalizedString*);
+ break;
+ }
+ case FT_STRING_NOT_LOCALIZED:
+ {
+ buffer << *(char const**)entry;
+ entry += sizeof(char const*);
+ break;
+ }
+ }
+ }
+ }
+ }
+
uint32 _tableHash;
+ uint32 _layoutHash;
+ std::string _fileName;
+ uint32 _fieldCount;
+ DB2Meta const* _meta;
+ char* _dataTable;
+ char* _dataTableEx;
+ std::vector<char*> _stringPool;
+ HotfixDatabaseStatements _hotfixStatement;
};
template<class T>
class DB2Storage : public DB2StorageBase
{
- typedef std::list<char*> StringPoolList;
+ 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)
- : _fileName(fileName), _indexTableSize(0), _fieldCount(0), _format(format), _dataTable(nullptr), _dataTableEx(nullptr), _hotfixStatement(preparedStmtIndex)
+ DB2Storage(char const* fileName, DB2Meta const* meta, HotfixDatabaseStatements preparedStmtIndex) : DB2StorageBase(fileName, meta, preparedStmtIndex),
+ _indexTableSize(0)
{
_indexTable.AsT = NULL;
}
@@ -57,69 +137,12 @@ public:
~DB2Storage()
{
delete[] reinterpret_cast<char*>(_indexTable.AsT);
- delete[] reinterpret_cast<char*>(_dataTable);
- delete[] reinterpret_cast<char*>(_dataTableEx);
- for (char* stringPool : _stringPoolList)
- delete[] stringPool;
}
bool HasRecord(uint32 id) const override { return id < _indexTableSize && _indexTable.AsT[id] != nullptr; }
void WriteRecord(uint32 id, uint32 locale, ByteBuffer& buffer) const override
{
- ASSERT(id < _indexTableSize);
- char const* entry = _indexTable.AsChar[id];
- ASSERT(entry);
-
- std::size_t fields = strlen(_format);
- for (uint32 i = 0; i < fields; ++i)
- {
- switch (_format[i])
- {
- case FT_IND:
- case FT_INT:
- buffer << *(uint32*)entry;
- entry += 4;
- break;
- case FT_FLOAT:
- buffer << *(float*)entry;
- entry += 4;
- break;
- case FT_BYTE:
- buffer << *(uint8*)entry;
- entry += 1;
- break;
- case FT_STRING:
- {
- LocalizedString* locStr = *(LocalizedString**)entry;
- if (locStr->Str[locale][0] == '\0')
- locale = 0;
-
- char const* str = locStr->Str[locale];
- std::size_t len = strlen(str);
- buffer << uint16(len ? len + 1 : 0);
- if (len)
- {
- buffer.append(str, len);
- buffer << uint8(0);
- }
- entry += sizeof(LocalizedString*);
- break;
- }
- case FT_STRING_NOT_LOCALIZED:
- {
- char const* str = *(char const**)entry;
- std::size_t len = strlen(str);
- buffer << uint16(len ? len + 1 : 0);
- if (len)
- {
- buffer.append(str, len);
- buffer << uint8(0);
- }
- entry += sizeof(char const*);
- break;
- }
- }
- }
+ WriteRecordData(reinterpret_cast<char const*>(AssertEntry(id)), locale, buffer);
}
void EraseRecord(uint32 id) override { if (id < _indexTableSize) _indexTable.AsT[id] = nullptr; }
@@ -127,38 +150,38 @@ public:
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
- if (!db2.Load((path + _fileName).c_str(), _format))
+ if (!db2.Load((path + _fileName).c_str(), _meta))
return false;
_fieldCount = db2.GetCols();
- _tableHash = db2.GetHash();
+ _tableHash = db2.GetTableHash();
+ _layoutHash = db2.GetLayoutHash();
// load raw non-string data
- _dataTable = reinterpret_cast<T*>(db2.AutoProduceData(_format, _indexTableSize, _indexTable.AsChar));
+ _dataTable = db2.AutoProduceData(_indexTableSize, _indexTable.AsChar);
// create string holders for loaded string fields
- if (char* stringHolders = db2.AutoProduceStringsArrayHolders(_format, (char*)_dataTable))
+ if (char* stringHolders = db2.AutoProduceStringsArrayHolders(_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(_dataTable, locale))
+ _stringPool.push_back(stringBlock);
}
+ db2.AutoProduceRecordCopies(_indexTableSize, _indexTable.AsChar, _dataTable);
+
// 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)
@@ -166,59 +189,145 @@ public:
DB2FileLoader db2;
// Check if load was successful, only then continue
- if (!db2.Load((path + _fileName).c_str(), _format))
+ if (!db2.Load((path + _fileName).c_str(), _meta))
return false;
// 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 (_meta->GetStringFieldCount(true))
+ if (char* stringBlock = db2.AutoProduceStrings(_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, _meta).Load(_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))
+ if (!_meta->GetStringFieldCount(true))
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, _meta).LoadStrings(HotfixDatabaseStatements(_hotfixStatement + 1), locale, _indexTableSize, _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 struct iterator_wrapper : public std::unordered_map<uint32, T const*>::const_iterator
+ {
+ typedef typename std::unordered_map<uint32, T const*>::const_iterator Base;
+
+ iterator_wrapper() = default;
+ iterator_wrapper(iterator_wrapper const& right) = default;
+ iterator_wrapper(Base const& baseItr) : Base(baseItr) { }
+
+ T const* operator->() const { return Base::operator->()->second; }
+ T const* operator*() const { return Base::operator*().second; }
+ } iterator;
+
+ DB2SparseStorage(char const* fileName, DB2Meta const* meta, HotfixDatabaseStatements preparedStmtIndex)
+ : DB2StorageBase(fileName, meta, 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(), _meta))
+ return false;
+
+ _fieldCount = db2.GetCols();
+ _tableHash = db2.GetTableHash();
+ _layoutHash = db2.GetLayoutHash();
+
+ // load raw non-string data
+ _dataTable = db2.AutoProduceData(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(), _meta))
+ return false;
+
+ // load strings from another locale db2 data
+ if (_meta->GetStringFieldCount(true))
+ if (char* stringBlock = db2.AutoProduceStrings(_dataTable, locale))
+ _stringPool.push_back(stringBlock);
+ return true;
+ }
+
+ void LoadFromDB() override
+ {
+ _dataTableEx = DB2SparseDatabaseLoader(_fileName, _meta).Load(_hotfixStatement, IndexTableAdapter<T>(_indexTable), _stringPool);
+ }
+
+ void LoadStringsFromDB(uint32 locale) override
+ {
+ if (!_meta->GetStringFieldCount(true))
+ return;
+
+ DB2SparseDatabaseLoader(_fileName, _meta).LoadStrings(HotfixDatabaseStatements(_hotfixStatement + 1), locale, IndexTableAdapter<T>(_indexTable), _stringPool);
+ }
+
+ iterator begin() const { return iterator(_indexTable.begin()); }
+ iterator end() const { return iterator(_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
deleted file mode 100644
index 829c3708221..00000000000
--- a/src/server/shared/DataStores/DBCFileLoader.cpp
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
- *
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "DBCFileLoader.h"
-#include "Errors.h"
-
-DBCFileLoader::DBCFileLoader() : recordSize(0), recordCount(0), fieldCount(0), stringSize(0), fieldsOffset(NULL), data(NULL), stringTable(NULL) { }
-
-bool DBCFileLoader::Load(const char* filename, const char* fmt)
-{
- uint32 header;
- if (data)
- {
- delete [] data;
- data = NULL;
- }
-
- FILE* f = fopen(filename, "rb");
- if (!f)
- return false;
-
- if (fread(&header, 4, 1, f) != 1) // Number of records
- {
- fclose(f);
- return false;
- }
-
-
- EndianConvert(header);
-
- if (header != 0x43424457) //'WDBC'
- {
- fclose(f);
- return false;
- }
-
- 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(&stringSize, 4, 1, f) != 1) // String size
- {
- fclose(f);
- return false;
- }
-
- 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] == FT_BYTE || fmt[i - 1] == FT_NA_BYTE) // byte fields
- fieldsOffset[i] += sizeof(uint8);
- else if (fmt[i - 1] == FT_LONG)
- fieldsOffset[i] += sizeof(uint64);
- else // 4 byte fields (int32/float/strings)
- fieldsOffset[i] += sizeof(uint32);
- }
-
- data = new unsigned char[recordSize * recordCount + stringSize];
- stringTable = data + recordSize*recordCount;
-
- if (fread(data, recordSize * recordCount + stringSize, 1, f) != 1)
- {
- fclose(f);
- return false;
- }
-
- fclose(f);
-
- return true;
-}
-
-DBCFileLoader::~DBCFileLoader()
-{
- delete[] data;
-
- delete[] fieldsOffset;
-}
-
-DBCFileLoader::Record DBCFileLoader::getRecord(size_t id)
-{
- assert(data);
- return Record(*this, data + id * recordSize);
-}
-
-uint32 DBCFileLoader::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:
- recordsize += sizeof(float);
- break;
- case FT_INT:
- recordsize += sizeof(uint32);
- break;
- case FT_STRING:
- recordsize += sizeof(char*);
- break;
- case FT_SORT:
- i = x;
- break;
- case FT_IND:
- i = x;
- recordsize += sizeof(uint32);
- break;
- case FT_BYTE:
- recordsize += sizeof(uint8);
- break;
- case FT_LONG:
- recordsize += sizeof(uint64);
- break;
- case FT_NA:
- case FT_NA_BYTE:
- break;
- default:
- ASSERT(false && "Unknown field format character in DBCfmt.h");
- break;
- }
- }
-
- if (index_pos)
- *index_pos = i;
-
- return recordsize;
-}
-
-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;
-
- //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;
- }
-
- // If higher index avalible from sql - use it instead of dbcs
- if (sqlHighestIndex > maxi)
- maxi = sqlHighestIndex;
-
- ++maxi;
- records = maxi;
- indexTable = new ptr[maxi];
- memset(indexTable, 0, maxi * sizeof(ptr));
- }
- else
- {
- records = recordCount + sqlRecordCount;
- indexTable = new ptr[recordCount + sqlRecordCount];
- }
-
- char* dataTable = new char[(recordCount + sqlRecordCount) * 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 += sizeof(float);
- break;
- case FT_IND:
- case FT_INT:
- *((uint32*)(&dataTable[offset])) = getRecord(y).getUInt(x);
- offset += sizeof(uint32);
- break;
- case FT_BYTE:
- *((uint8*)(&dataTable[offset])) = getRecord(y).getUInt8(x);
- offset += sizeof(uint8);
- break;
- case FT_LONG:
- *((uint64*)(&dataTable[offset])) = getRecord(y).getUInt64(x);
- offset += sizeof(uint64);
- break;
- case FT_STRING:
- *((char**)(&dataTable[offset])) = NULL; // will replace non-empty or "" strings in AutoProduceStrings
- offset += sizeof(char*);
- break;
- case FT_NA:
- case FT_NA_BYTE:
- case FT_SORT:
- break;
- default:
- ASSERT(false && "Unknown field format character in DBCfmt.h");
- break;
- }
- }
- }
-
- sqlDataTable = dataTable + offset;
-
- return dataTable;
-}
-
-char* DBCFileLoader::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:
- offset += sizeof(float);
- break;
- case FT_IND:
- case FT_INT:
- offset += sizeof(uint32);
- break;
- case FT_BYTE:
- offset += sizeof(uint8);
- break;
- case FT_LONG:
- offset += sizeof(uint64);
- 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;
- }
- case FT_NA:
- case FT_NA_BYTE:
- case FT_SORT:
- break;
- default:
- ASSERT(false && "Unknown field format character in DBCfmt.h");
- break;
- }
- }
- }
-
- return stringPool;
-}
diff --git a/src/server/shared/DataStores/DBCFileLoader.h b/src/server/shared/DataStores/DBCFileLoader.h
deleted file mode 100644
index e58031e6ccc..00000000000
--- a/src/server/shared/DataStores/DBCFileLoader.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
- *
- * 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 DBC_FILE_LOADER_H
-#define DBC_FILE_LOADER_H
-
-#include "Define.h"
-#include "Utilities/ByteConverter.h"
-#include <cassert>
-
-class TC_SHARED_API DBCFileLoader
-{
- public:
- DBCFileLoader();
- ~DBCFileLoader();
-
- 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));
- }
- uint64 getUInt64(size_t field) const
- {
- assert(field < file.fieldCount);
- uint64 val = *reinterpret_cast<uint64*>(offset + file.GetOffset(field));
- EndianConvert(val);
- return val;
- }
- 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(DBCFileLoader &file_, unsigned char *offset_): offset(offset_), file(file_) { }
- unsigned char* offset;
- DBCFileLoader& file;
-
- friend class DBCFileLoader;
-
- };
-
- // Get record by id
- Record getRecord(size_t id);
- /// Get begin iterator over records
-
- uint32 GetNumRows() const { return recordCount; }
- uint32 GetRowSize() const { return recordSize; }
- uint32 GetCols() const { return fieldCount; }
- uint32 GetOffset(size_t id) const { return (fieldsOffset != NULL && id < fieldCount) ? fieldsOffset[id] : 0; }
- bool IsLoaded() const { return data != NULL; }
- char* AutoProduceData(const char* fmt, uint32& count, char**& indexTable, uint32 sqlRecordCount, uint32 sqlHighestIndex, char *& sqlDataTable);
- 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;
-
- DBCFileLoader(DBCFileLoader const& right) = delete;
- DBCFileLoader& operator=(DBCFileLoader const& right) = delete;
-};
-#endif
diff --git a/src/server/shared/DataStores/DBCStore.h b/src/server/shared/DataStores/DBCStore.h
deleted file mode 100644
index c53d2a563fe..00000000000
--- a/src/server/shared/DataStores/DBCStore.h
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
- *
- * 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 DBCSTORE_H
-#define DBCSTORE_H
-
-#include "DBCFileLoader.h"
-#include "DBStorageIterator.h"
-#include "Log.h"
-#include "Field.h"
-#include "DatabaseWorkerPool.h"
-#include "Implementation/WorldDatabase.h"
-#include "DatabaseEnv.h"
-
-struct SqlDbc
-{
- std::string const* formatString;
- std::string const* indexName;
- std::string sqlTableName;
- int32 indexPos;
- int32 sqlIndexPos;
- SqlDbc(std::string const* _filename, std::string const* _format, std::string const* _idname, char const* fmt)
- : formatString(_format), indexName (_idname), sqlIndexPos(0)
- {
- // Convert dbc file name to sql table name
- sqlTableName = *_filename;
- for (uint32 i = 0; i< sqlTableName.size(); ++i)
- {
- if (isalpha(sqlTableName[i]))
- sqlTableName[i] = char(tolower(sqlTableName[i]));
- else if (sqlTableName[i] == '.')
- sqlTableName[i] = '_';
- }
-
- // Get sql index position
- DBCFileLoader::GetFormatRecordSize(fmt, &indexPos);
- if (indexPos >= 0)
- {
- uint32 uindexPos = uint32(indexPos);
- for (uint32 x = 0; x < formatString->size(); ++x)
- {
- // Count only fields present in sql
- if ((*formatString)[x] == FT_SQL_PRESENT)
- {
- if (x == uindexPos)
- break;
- ++sqlIndexPos;
- }
- }
- }
- }
-
-private:
- SqlDbc(SqlDbc const& right) = delete;
- SqlDbc& operator=(SqlDbc const& right) = delete;
-};
-
-template<class T>
-class DBCStorage
-{
- typedef std::list<char*> StringPoolList;
-
- public:
- typedef DBStorageIterator<T> iterator;
-
- explicit DBCStorage(char const* f)
- : fmt(f), nCount(0), fieldCount(0), dataTable(NULL)
- {
- indexTable.asT = NULL;
- }
-
- ~DBCStorage() { Clear(); }
-
- T const* LookupEntry(uint32 id) const
- {
- return (id >= nCount) ? NULL : indexTable.asT[id];
- }
-
- T const* AssertEntry(uint32 id) const
- {
- T const* entry = LookupEntry(id);
- ASSERT(entry);
- return entry;
- }
-
- uint32 GetNumRows() const { return nCount; }
- char const* GetFormat() const { return fmt; }
- uint32 GetFieldCount() const { return fieldCount; }
-
- bool Load(char const* fn, SqlDbc* sql)
- {
- DBCFileLoader dbc;
- // Check if load was successful, only then continue
- if (!dbc.Load(fn, fmt))
- return false;
-
- uint32 sqlRecordCount = 0;
- uint32 sqlHighestIndex = 0;
- Field* fields = NULL;
- QueryResult result = QueryResult(NULL);
- // Load data from sql
- if (sql)
- {
- std::string query = "SELECT * FROM " + sql->sqlTableName;
- if (sql->indexPos >= 0)
- query +=" ORDER BY " + *sql->indexName + " DESC";
- query += ';';
-
-
- result = WorldDatabase.Query(query.c_str());
- if (result)
- {
- sqlRecordCount = uint32(result->GetRowCount());
- if (sql->indexPos >= 0)
- {
- fields = result->Fetch();
- sqlHighestIndex = fields[sql->sqlIndexPos].GetUInt32();
- }
-
- // Check if sql index pos is valid
- if (int32(result->GetFieldCount() - 1) < sql->sqlIndexPos)
- {
- TC_LOG_ERROR("server.loading", "Invalid index pos for dbc:'%s'", sql->sqlTableName.c_str());
- return false;
- }
- }
- }
-
- char* sqlDataTable = NULL;
- fieldCount = dbc.GetCols();
-
- dataTable = reinterpret_cast<T*>(dbc.AutoProduceData(fmt, nCount, indexTable.asChar,
- sqlRecordCount, sqlHighestIndex, sqlDataTable));
-
- stringPoolList.push_back(dbc.AutoProduceStrings(fmt, reinterpret_cast<char*>(dataTable)));
-
- // Insert sql data into arrays
- if (result)
- {
- if (indexTable.asT)
- {
- uint32 offset = 0;
- uint32 rowIndex = dbc.GetNumRows();
- do
- {
- if (!fields)
- fields = result->Fetch();
-
- if (sql->indexPos >= 0)
- {
- uint32 id = fields[sql->sqlIndexPos].GetUInt32();
- if (indexTable.asT[id])
- {
- TC_LOG_ERROR("server.loading", "Index %d already exists in dbc:'%s'", id, sql->sqlTableName.c_str());
- return false;
- }
-
- indexTable.asT[id] = reinterpret_cast<T*>(&sqlDataTable[offset]);
- }
- else
- indexTable.asT[rowIndex]= reinterpret_cast<T*>(&sqlDataTable[offset]);
-
- uint32 columnNumber = 0;
- uint32 sqlColumnNumber = 0;
-
- for (; columnNumber < sql->formatString->size(); ++columnNumber)
- {
- if ((*sql->formatString)[columnNumber] == FT_SQL_ABSENT)
- {
- switch (fmt[columnNumber])
- {
- case FT_FLOAT:
- *reinterpret_cast<float*>(&sqlDataTable[offset]) = 0.0f;
- offset += 4;
- break;
- case FT_IND:
- case FT_INT:
- *reinterpret_cast<uint32*>(&sqlDataTable[offset]) = uint32(0);
- offset += 4;
- break;
- case FT_BYTE:
- *reinterpret_cast<uint8*>(&sqlDataTable[offset]) = uint8(0);
- offset += 1;
- break;
- case FT_LONG:
- *reinterpret_cast<uint64*>(&sqlDataTable[offset]) = uint64(0);
- offset += 8;
- break;
- case FT_STRING:
- // Beginning of the pool - empty string
- *reinterpret_cast<char**>(&sqlDataTable[offset]) = stringPoolList.back();
- offset += sizeof(char*);
- break;
- }
- }
- else if ((*sql->formatString)[columnNumber] == FT_SQL_PRESENT)
- {
- bool validSqlColumn = true;
- switch (fmt[columnNumber])
- {
- case FT_FLOAT:
- *reinterpret_cast<float*>(&sqlDataTable[offset]) = fields[sqlColumnNumber].GetFloat();
- offset += 4;
- break;
- case FT_IND:
- case FT_INT:
- *reinterpret_cast<uint32*>(&sqlDataTable[offset]) = fields[sqlColumnNumber].GetUInt32();
- offset += 4;
- break;
- case FT_BYTE:
- *reinterpret_cast<uint8*>(&sqlDataTable[offset]) = fields[sqlColumnNumber].GetUInt8();
- offset += 1;
- break;
- case FT_LONG:
- *reinterpret_cast<uint64*>(&sqlDataTable[offset]) = fields[sqlColumnNumber].GetUInt64();
- offset += 8;
- break;
- case FT_STRING:
- TC_LOG_ERROR("server.loading", "Unsupported data type in table '%s' at char %d", sql->sqlTableName.c_str(), columnNumber);
- return false;
- case FT_SORT:
- break;
- default:
- validSqlColumn = false;
- break;
- }
- if (validSqlColumn && (columnNumber != (sql->formatString->size()-1)))
- sqlColumnNumber++;
- }
- else
- {
- TC_LOG_ERROR("server.loading", "Incorrect sql format string '%s' at char %d", sql->sqlTableName.c_str(), columnNumber);
- return false;
- }
- }
-
- if (sqlColumnNumber != (result->GetFieldCount() - 1))
- {
- TC_LOG_ERROR("server.loading", "SQL and DBC format strings are not matching for table: '%s'", sql->sqlTableName.c_str());
- return false;
- }
-
- fields = NULL;
- ++rowIndex;
- } while (result->NextRow());
- }
- }
-
- // error in dbc file at loading if NULL
- return indexTable.asT != NULL;
- }
-
- bool LoadStringsFrom(char const* fn)
- {
- // DBC must be already loaded using Load
- if (!indexTable.asT)
- return false;
-
- DBCFileLoader dbc;
- // Check if load was successful, only then continue
- if (!dbc.Load(fn, fmt))
- return false;
-
- stringPoolList.push_back(dbc.AutoProduceStrings(fmt, reinterpret_cast<char*>(dataTable)));
-
- return true;
- }
-
- void Clear()
- {
- if (!indexTable.asT)
- return;
-
- delete[] reinterpret_cast<char*>(indexTable.asT);
- indexTable.asT = NULL;
- delete[] reinterpret_cast<char*>(dataTable);
- dataTable = NULL;
-
- while (!stringPoolList.empty())
- {
- delete[] stringPoolList.front();
- stringPoolList.pop_front();
- }
-
- nCount = 0;
- }
-
- iterator begin() { return iterator(indexTable.asT, nCount); }
- iterator end() { return iterator(indexTable.asT, nCount, nCount); }
-
- private:
- char const* fmt;
- uint32 nCount;
- uint32 fieldCount;
-
- union
- {
- T** asT;
- char** asChar;
- }
- indexTable;
-
- T* dataTable;
- StringPoolList stringPoolList;
-
- DBCStorage(DBCStorage const& right) = delete;
- DBCStorage& operator=(DBCStorage const& right) = delete;
-};
-
-#endif
diff --git a/src/server/shared/DataStores/DBStorageIterator.h b/src/server/shared/DataStores/DBStorageIterator.h
index 8148a2a5300..5568397b245 100644
--- a/src/server/shared/DataStores/DBStorageIterator.h
+++ b/src/server/shared/DataStores/DBStorageIterator.h
@@ -35,8 +35,8 @@ public:
}
}
- T* operator->() { return _index[_pos]; }
- T* operator*() { 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); }