diff options
| author | ariel- <ariel-@users.noreply.github.com> | 2017-06-19 23:20:06 -0300 |
|---|---|---|
| committer | ariel- <ariel-@users.noreply.github.com> | 2017-06-19 23:20:06 -0300 |
| commit | 85a7d5ce9ac68b30da2277cc91d4b70358f1880d (patch) | |
| tree | df3d2084ee2e35008903c03178039b9c986e2d08 /src/server/shared/DataStores | |
| parent | 052fc24315ace866ea1cf610e85df119b68100c9 (diff) | |
Core: ported headers cleanup from master branch
Diffstat (limited to 'src/server/shared/DataStores')
| -rw-r--r-- | src/server/shared/DataStores/DBCDatabaseLoader.cpp | 193 | ||||
| -rw-r--r-- | src/server/shared/DataStores/DBCDatabaseLoader.h | 43 | ||||
| -rw-r--r-- | src/server/shared/DataStores/DBCFileLoader.cpp | 322 | ||||
| -rw-r--r-- | src/server/shared/DataStores/DBCFileLoader.h | 113 | ||||
| -rw-r--r-- | src/server/shared/DataStores/DBCStorageIterator.h | 69 | ||||
| -rw-r--r-- | src/server/shared/DataStores/DBCStore.cpp | 76 | ||||
| -rw-r--r-- | src/server/shared/DataStores/DBCStore.h | 306 |
7 files changed, 431 insertions, 691 deletions
diff --git a/src/server/shared/DataStores/DBCDatabaseLoader.cpp b/src/server/shared/DataStores/DBCDatabaseLoader.cpp new file mode 100644 index 00000000000..3ef3e8f64c0 --- /dev/null +++ b/src/server/shared/DataStores/DBCDatabaseLoader.cpp @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2008-2017 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 "DBCDatabaseLoader.h" +#include "Common.h" +#include "DatabaseEnv.h" +#include "Errors.h" +#include "Log.h" +#include <sstream> + +DBCDatabaseLoader::DBCDatabaseLoader(std::string const& storageName, std::string const& dbFormatString, std::string const& primaryKey, char const* dbcFormatString) + : _formatString(dbFormatString), _indexName(primaryKey), _sqlTableName(storageName), _dbcFormat(dbcFormatString), _sqlIndexPos(0), _recordSize(0) +{ + // Convert dbc file name to sql table name + std::transform(_sqlTableName.begin(), _sqlTableName.end(), _sqlTableName.begin(), ::tolower); + for (char& c : _sqlTableName) + if (c == '.') + c = '_'; + + // Get sql index position + int32 indexPos = -1; + _recordSize = DBCFileLoader::GetFormatRecordSize(_dbcFormat, &indexPos); + ASSERT(indexPos >= 0); + ASSERT(_recordSize); + + 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; + } + } +} + +static char const* nullStr = ""; + +char* DBCDatabaseLoader::Load(uint32& records, char**& indexTable) +{ + std::ostringstream queryBuilder; + queryBuilder << "SELECT * FROM " << _sqlTableName + << " ORDER BY " << _indexName << " DESC;"; + + // no error if empty set + QueryResult result = WorldDatabase.Query(queryBuilder.str().c_str()); + if (!result) + return nullptr; + + // Check if sql index pos is valid + if (int32(result->GetFieldCount() - 1) < _sqlIndexPos) + { + ASSERT(false, "Invalid index pos for dbc:'%s'", _sqlTableName.c_str()); + return nullptr; + } + + // Resize index table + // database query *MUST* contain ORDER BY `index_field` DESC clause + uint32 indexTableSize = std::max(records, (*result)[_sqlIndexPos].GetUInt32() + 1); + if (indexTableSize > records) + { + char** tmpIdxTable = new char*[indexTableSize]; + memset(tmpIdxTable, 0, indexTableSize * sizeof(char*)); + memcpy(tmpIdxTable, indexTable, records * sizeof(char*)); + delete[] indexTable; + indexTable = tmpIdxTable; + } + + std::unique_ptr<char[]> dataTable = Trinity::make_unique<char[]>(result->GetRowCount() * _recordSize); + std::unique_ptr<uint32[]> newIndexes = Trinity::make_unique<uint32[]>(result->GetRowCount()); + uint32 newRecords = 0; + + // Insert sql data into the data array + do + { + Field* fields = result->Fetch(); + uint32 offset = 0; + + uint32 indexValue = fields[_sqlIndexPos].GetUInt32(); + + char* dataValue = indexTable[indexValue]; + if (!dataValue) + { + newIndexes[newRecords] = indexValue; + dataValue = &dataTable[newRecords++ * _recordSize]; + } + else + { + // Attempt to overwrite existing data + ASSERT(false, "Index %d already exists in dbc:'%s'", indexValue, _sqlTableName.c_str()); + return nullptr; + } + + uint32 columnNumber = 0; + uint32 sqlColumnNumber = 0; + + for (; columnNumber < _formatString.size(); ++columnNumber) + { + if (_formatString[columnNumber] == FT_SQL_ABSENT) + { + switch (_dbcFormat[columnNumber]) + { + case FT_FLOAT: + *reinterpret_cast<float*>(&dataValue[offset]) = 0.0f; + offset += 4; + break; + case FT_IND: + case FT_INT: + *reinterpret_cast<uint32*>(&dataValue[offset]) = uint32(0); + offset += 4; + break; + case FT_BYTE: + *reinterpret_cast<uint8*>(&dataValue[offset]) = uint8(0); + offset += 1; + break; + case FT_STRING: + *reinterpret_cast<char**>(&dataValue[offset]) = const_cast<char*>(nullStr); + offset += sizeof(char*); + break; + } + } + else if (_formatString[columnNumber] == FT_SQL_PRESENT) + { + bool validSqlColumn = true; + switch (_dbcFormat[columnNumber]) + { + case FT_FLOAT: + *reinterpret_cast<float*>(&dataValue[offset]) = fields[sqlColumnNumber].GetFloat(); + offset += 4; + break; + case FT_IND: + case FT_INT: + *reinterpret_cast<uint32*>(&dataValue[offset]) = fields[sqlColumnNumber].GetUInt32(); + offset += 4; + break; + case FT_BYTE: + *reinterpret_cast<uint8*>(&dataValue[offset]) = fields[sqlColumnNumber].GetUInt8(); + offset += 1; + break; + case FT_STRING: + ASSERT(false, "Unsupported data type in table '%s' at char %d", _sqlTableName.c_str(), columnNumber); + return nullptr; + case FT_SORT: + break; + default: + validSqlColumn = false; + break; + } + if (validSqlColumn && (columnNumber != (_formatString.size() - 1))) + sqlColumnNumber++; + } + else + { + ASSERT(false, "Incorrect sql format string '%s' at char %d", _sqlTableName.c_str(), columnNumber); + break; + } + } + + if (sqlColumnNumber != (result->GetFieldCount() - 1)) + { + ASSERT(false, "SQL and DBC format strings are not matching for table: '%s'", _sqlTableName.c_str()); + return nullptr; + } + + ASSERT(offset == _recordSize); + } while (result->NextRow()); + + ASSERT(newRecords == result->GetRowCount()); + + // insert new records to index table + for (uint32 i = 0; i < newRecords; ++i) + indexTable[newIndexes[i]] = &dataTable[i * _recordSize]; + + records = indexTableSize; + + return dataTable.release(); +} diff --git a/src/server/shared/DataStores/DBCDatabaseLoader.h b/src/server/shared/DataStores/DBCDatabaseLoader.h new file mode 100644 index 00000000000..153a0eb4dcb --- /dev/null +++ b/src/server/shared/DataStores/DBCDatabaseLoader.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008-2017 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 DBCDatabaseLoader_h__ +#define DBCDatabaseLoader_h__ + +#include "DBCFileLoader.h" +#include <string> +#include <vector> + +struct TC_SHARED_API DBCDatabaseLoader +{ + DBCDatabaseLoader(std::string const& storageName, std::string const& dbFormatString, std::string const& primaryKey, char const* dbcFormatString); + + char* Load(uint32& records, char**& indexTable); + +private: + std::string const& _formatString; + std::string const& _indexName; + std::string _sqlTableName; + char const* _dbcFormat; + int32 _sqlIndexPos; + uint32 _recordSize; + + DBCDatabaseLoader(DBCDatabaseLoader const& right) = delete; + DBCDatabaseLoader& operator=(DBCDatabaseLoader const& right) = delete; +}; + +#endif // DBCDatabaseLoader_h__ diff --git a/src/server/shared/DataStores/DBCFileLoader.cpp b/src/server/shared/DataStores/DBCFileLoader.cpp deleted file mode 100644 index 8c92260e62d..00000000000 --- a/src/server/shared/DataStores/DBCFileLoader.cpp +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (C) 2008-2017 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] == 'b' || fmt[i - 1] == 'X') // byte fields - fieldsOffset[i] += sizeof(uint8); - 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_NA: - case FT_NA_BYTE: - break; - case FT_LOGIC: - ASSERT(false && "Attempted to load DBC files that do not have field types that match what is in the core. Check DBCfmt.h or your DBC files."); - 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_STRING: - *((char**)(&dataTable[offset])) = NULL; // will replace non-empty or "" strings in AutoProduceStrings - offset += sizeof(char*); - break; - case FT_LOGIC: - ASSERT(false && "Attempted to load DBC files that do not have field types that match what is in the core. Check DBCfmt.h or your DBC files."); - 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_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_LOGIC: - ASSERT(false && "Attempted to load DBC files that does not have field types that match what is in the core. Check DBCfmt.h or your DBC files."); - 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 1c005a9e670..00000000000 --- a/src/server/shared/DataStores/DBCFileLoader.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2008-2017 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> - -enum DbcFieldFormat -{ - FT_NA='x', //not used or unknown, 4 byte size - FT_NA_BYTE='X', //not used or unknown, byte - FT_STRING='s', //char* - FT_FLOAT='f', //float - FT_INT='i', //uint32 - FT_BYTE='b', //uint8 - FT_SORT='d', //sorted by this field, field is not included - FT_IND='n', //the same, but parsed to data - FT_LOGIC='l', //Logical (boolean) - FT_SQL_PRESENT='p', //Used in sql format to mark column present in sql dbc - FT_SQL_ABSENT='a' //Used in sql format to mark column absent in sql dbc -}; - -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)); - } - - 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/DBCStorageIterator.h b/src/server/shared/DataStores/DBCStorageIterator.h new file mode 100644 index 00000000000..be1e58db967 --- /dev/null +++ b/src/server/shared/DataStores/DBCStorageIterator.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2008-2017 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 DBCStorageIterator_h__ +#define DBCStorageIterator_h__ + +#include "Define.h" +#include <iterator> + +template <class T> +class DBCStorageIterator : public std::iterator<std::forward_iterator_tag, T> +{ + public: + DBCStorageIterator() : _index(nullptr), _pos(0), _end(0) { } + DBCStorageIterator(T** index, uint32 size, uint32 pos = 0) : _index(index), _pos(pos), _end(size) + { + if (_pos < _end) + { + while (_pos < _end && !_index[_pos]) + ++_pos; + } + } + + T const* operator->() { return _index[_pos]; } + T const* operator*() { return _index[_pos]; } + + bool operator==(DBCStorageIterator const& right) const { /*ASSERT(_index == right._index, "Iterator belongs to a different container")*/ return _pos == right._pos; } + bool operator!=(DBCStorageIterator const& right) const { return !(*this == right); } + + DBCStorageIterator& operator++() + { + if (_pos < _end) + { + do + ++_pos; + while (_pos < _end && !_index[_pos]); + } + + return *this; + } + + DBCStorageIterator operator++(int) + { + DBCStorageIterator tmp = *this; + ++*this; + return tmp; + } + + private: + T** _index; + uint32 _pos; + uint32 _end; +}; + +#endif // DBCStorageIterator_h__ diff --git a/src/server/shared/DataStores/DBCStore.cpp b/src/server/shared/DataStores/DBCStore.cpp new file mode 100644 index 00000000000..30cae057f90 --- /dev/null +++ b/src/server/shared/DataStores/DBCStore.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2008-2017 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 "DBCStore.h" +#include "DBCDatabaseLoader.h" + +DBCStorageBase::DBCStorageBase(char const* fmt) : _fieldCount(0), _fileFormat(fmt), _dataTable(nullptr), _indexTableSize(0) +{ +} + +DBCStorageBase::~DBCStorageBase() +{ + delete[] _dataTable; + delete[] _dataTableEx; + for (char* strings : _stringPool) + delete[] strings; +} + +bool DBCStorageBase::Load(std::string const& path, char**& indexTable) +{ + indexTable = nullptr; + + DBCFileLoader dbc; + // Check if load was sucessful, only then continue + if (!dbc.Load(path.c_str(), _fileFormat)) + return false; + + _fieldCount = dbc.GetCols(); + + // load raw non-string data + _dataTable = dbc.AutoProduceData(_fileFormat, _indexTableSize, indexTable); + + // load strings from dbc data + if (char* stringBlock = dbc.AutoProduceStrings(_fileFormat, _dataTable)) + _stringPool.push_back(stringBlock); + + // error in dbc file at loading if NULL + return indexTable != nullptr; +} + +bool DBCStorageBase::LoadStringsFrom(std::string const& path, char** indexTable) +{ + // DBC must be already loaded using Load + if (!indexTable) + return false; + + DBCFileLoader dbc; + // Check if load was successful, only then continue + if (!dbc.Load(path.c_str(), _fileFormat)) + return false; + + // load strings from another locale dbc data + if (char* stringBlock = dbc.AutoProduceStrings(_fileFormat, _dataTable)) + _stringPool.push_back(stringBlock); + + return true; +} + +void DBCStorageBase::LoadFromDB(std::string const& path, std::string const& dbFormat, std::string const& primaryKey, char**& indexTable) +{ + _dataTableEx = DBCDatabaseLoader(path, dbFormat, primaryKey, _fileFormat).Load(_indexTableSize, indexTable); +} diff --git a/src/server/shared/DataStores/DBCStore.h b/src/server/shared/DataStores/DBCStore.h index b11bb0b74d4..e04f434cf89 100644 --- a/src/server/shared/DataStores/DBCStore.h +++ b/src/server/shared/DataStores/DBCStore.h @@ -19,289 +19,83 @@ #ifndef DBCSTORE_H #define DBCSTORE_H -#include "DBCFileLoader.h" -#include "Logging/Log.h" -#include "Field.h" -#include "DatabaseWorkerPool.h" -#include "Implementation/WorldDatabase.h" -#include "DatabaseEnv.h" +#include "Common.h" +#include "DBCStorageIterator.h" +#include <vector> -struct SqlDbc + /// Interface class for common access +class TC_SHARED_API DBCStorageBase { - 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; + public: + DBCStorageBase(char const* fmt); + virtual ~DBCStorageBase(); + + char const* GetFormat() const { return _fileFormat; } + uint32 GetFieldCount() const { return _fieldCount; } + + virtual bool Load(std::string const& path) = 0; + virtual bool LoadStringsFrom(std::string const& path) = 0; + virtual void LoadFromDB(std::string const& path, std::string const& dbFormat, std::string const& primaryKey) = 0; + + protected: + bool Load(std::string const& path, char**& indexTable); + bool LoadStringsFrom(std::string const& path, char** indexTable); + void LoadFromDB(std::string const& path, std::string const& dbFormat, std::string const& primaryKey, char**& indexTable); + + uint32 _fieldCount; + char const* _fileFormat; + char* _dataTable; + char* _dataTableEx; + std::vector<char*> _stringPool; + uint32 _indexTableSize; }; -template<class T> -class DBCStorage +template <class T> +class DBCStorage : public DBCStorageBase { - typedef std::list<char*> StringPoolList; public: - explicit DBCStorage(char const* f) - : fmt(f), nCount(0), fieldCount(0), dataTable(NULL) - { - indexTable.asT = NULL; - } + typedef DBCStorageIterator<T> iterator; - ~DBCStorage() { Clear(); } - - T const* LookupEntry(uint32 id) const + explicit DBCStorage(char const* fmt) : DBCStorageBase(fmt) { - return (id >= nCount) ? NULL : indexTable.asT[id]; + _indexTable.AsT = nullptr; } - T const* AssertEntry(uint32 id) const + ~DBCStorage() { - T const* entry = LookupEntry(id); - ASSERT(entry); - return entry; + delete[] reinterpret_cast<char*>(_indexTable.AsT); } - 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 sucessful, 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)); + T const* LookupEntry(uint32 id) const { return (id >= _indexTableSize) ? nullptr : _indexTable.AsT[id]; } + T const* AssertEntry(uint32 id) const { return ASSERT_NOTNULL(LookupEntry(id)); } - stringPoolList.push_back(dbc.AutoProduceStrings(fmt, reinterpret_cast<char*>(dataTable))); + uint32 GetNumRows() const { return _indexTableSize; } - // 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_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_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 Load(std::string const& path) override + { + return DBCStorageBase::Load(path, _indexTable.AsChar); } - bool LoadStringsFrom(char const* fn) + bool LoadStringsFrom(std::string const& path) override { - // 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; + return DBCStorageBase::LoadStringsFrom(path, _indexTable.AsChar); } - void Clear() + void LoadFromDB(std::string const& path, std::string const& dbFormat, std::string const& primaryKey) override { - 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; + DBCStorageBase::LoadFromDB(path, dbFormat, primaryKey, _indexTable.AsChar); } - private: - char const* fmt; - uint32 nCount; - uint32 fieldCount; + iterator begin() { return iterator(_indexTable.AsT, _indexTableSize); } + iterator end() { return iterator(_indexTable.AsT, _indexTableSize, _indexTableSize); } + private: union { - T** asT; - char** asChar; + T** AsT; + char** AsChar; } - indexTable; - - T* dataTable; - StringPoolList stringPoolList; + _indexTable; DBCStorage(DBCStorage const& right) = delete; DBCStorage& operator=(DBCStorage const& right) = delete; |
