mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-15 23:20:36 +01:00
Core/DataStores: Refactor DB2 loaders to be reusable by extractors
This commit is contained in:
301
src/server/shared/DataStores/DB2DatabaseLoader.cpp
Normal file
301
src/server/shared/DataStores/DB2DatabaseLoader.cpp
Normal file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* 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 "DB2DatabaseLoader.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "DB2Meta.h"
|
||||
|
||||
DB2LoadInfo::DB2LoadInfo() : DB2FileLoadInfo()
|
||||
{
|
||||
}
|
||||
|
||||
DB2LoadInfo::DB2LoadInfo(DB2FieldMeta const* fields, std::size_t fieldCount, DB2Meta const* meta, HotfixDatabaseStatements statement)
|
||||
: DB2FileLoadInfo(fields, fieldCount, meta), Statement(statement)
|
||||
{
|
||||
}
|
||||
|
||||
static char const* nullStr = "";
|
||||
|
||||
char* DB2DatabaseLoader::Load(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(_loadInfo->Statement));
|
||||
if (!result)
|
||||
return nullptr;
|
||||
|
||||
if (_loadInfo->Meta->GetDbFieldCount() != result->GetFieldCount())
|
||||
return nullptr;
|
||||
|
||||
// get struct size and index pos
|
||||
uint32 indexField = _loadInfo->Meta->GetDbIndexField();
|
||||
uint32 recordSize = _loadInfo->Meta->GetRecordSize();
|
||||
|
||||
// we store flat holders pool as single memory block
|
||||
std::size_t stringFields = _loadInfo->GetStringFieldCount(false);
|
||||
std::size_t localizedStringFields = _loadInfo->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*);
|
||||
|
||||
if (stringFields)
|
||||
{
|
||||
std::size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * result->GetRowCount();
|
||||
stringHolders = new char[stringHoldersPoolSize];
|
||||
|
||||
// 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;
|
||||
}
|
||||
else
|
||||
stringHolders = nullptr;
|
||||
|
||||
// Resize index table
|
||||
// database query *MUST* contain ORDER BY `index_field` DESC clause
|
||||
uint32 indexTableSize = (*result)[indexField].GetUInt32() + 1;
|
||||
if (indexTableSize < records)
|
||||
indexTableSize = records;
|
||||
|
||||
if (indexTableSize > records)
|
||||
{
|
||||
char** tmpIdxTable = new char*[indexTableSize];
|
||||
memset(tmpIdxTable, 0, indexTableSize * sizeof(char*));
|
||||
memcpy(tmpIdxTable, indexTable, records * sizeof(char*));
|
||||
delete[] indexTable;
|
||||
indexTable = tmpIdxTable;
|
||||
}
|
||||
|
||||
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[indexValue];
|
||||
if (!dataValue)
|
||||
{
|
||||
newIndexes[newRecords] = indexValue;
|
||||
dataValue = &tempDataTable[newRecords++ * recordSize];
|
||||
}
|
||||
|
||||
uint32 f = 0;
|
||||
if (!_loadInfo->Meta->HasIndexFieldInData())
|
||||
{
|
||||
*((uint32*)(&dataValue[offset])) = indexValue;
|
||||
offset += 4;
|
||||
++f;
|
||||
}
|
||||
|
||||
for (uint32 x = 0; x < _loadInfo->Meta->FieldCount; ++x)
|
||||
{
|
||||
for (uint32 z = 0; z < _loadInfo->Meta->ArraySizes[x]; ++z)
|
||||
{
|
||||
switch (_loadInfo->TypesString[f])
|
||||
{
|
||||
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", _loadInfo->TypesString[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[newIndexes[i]] = &dataTable[i * recordSize];
|
||||
|
||||
delete[] tempDataTable;
|
||||
delete[] newIndexes;
|
||||
|
||||
records = indexTableSize;
|
||||
|
||||
return dataTable;
|
||||
}
|
||||
|
||||
void DB2DatabaseLoader::LoadStrings(uint32 locale, uint32 records, char** indexTable, std::vector<char*>& stringPool)
|
||||
{
|
||||
PreparedStatement* stmt = HotfixDatabase.GetPreparedStatement(HotfixDatabaseStatements(_loadInfo->Statement + 1));
|
||||
stmt->setString(0, localeNames[locale]);
|
||||
PreparedQueryResult result = HotfixDatabase.Query(stmt);
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
std::size_t stringFields = _loadInfo->GetStringFieldCount(true);
|
||||
if (result->GetFieldCount() != stringFields + 1 /*ID*/)
|
||||
return;
|
||||
|
||||
uint32 fieldCount = _loadInfo->Meta->FieldCount;
|
||||
uint32 recordSize = _loadInfo->Meta->GetRecordSize();
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 offset = 0;
|
||||
uint32 stringFieldNumInRecord = 0;
|
||||
uint32 indexValue = fields[0].GetUInt32();
|
||||
|
||||
if (indexValue >= records)
|
||||
continue;
|
||||
|
||||
// Attempt to overwrite existing data
|
||||
if (char* dataValue = indexTable[indexValue])
|
||||
{
|
||||
uint32 fieldIndex = 0;
|
||||
if (!_loadInfo->Meta->HasIndexFieldInData())
|
||||
{
|
||||
offset += 4;
|
||||
++fieldIndex;
|
||||
}
|
||||
|
||||
for (uint32 x = 0; x < fieldCount; ++x)
|
||||
{
|
||||
for (uint32 z = 0; z < _loadInfo->Meta->ArraySizes[x]; ++z)
|
||||
{
|
||||
switch (_loadInfo->TypesString[fieldIndex])
|
||||
{
|
||||
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", _loadInfo->TypesString[x], _storageName.c_str());
|
||||
break;
|
||||
}
|
||||
++fieldIndex;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(offset == recordSize);
|
||||
}
|
||||
else
|
||||
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());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
char* DB2DatabaseLoader::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;
|
||||
}
|
||||
@@ -15,67 +15,18 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DB2_FILE_LOADER_H
|
||||
#define DB2_FILE_LOADER_H
|
||||
#ifndef DB2_DATABASE_LOADER_H
|
||||
#define DB2_DATABASE_LOADER_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "DB2FileLoader.h"
|
||||
#include "Implementation/HotfixDatabase.h"
|
||||
|
||||
class DB2FileLoaderImpl;
|
||||
struct DB2Meta;
|
||||
struct DB2FieldMeta;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct DB2Header
|
||||
{
|
||||
uint32 Signature;
|
||||
uint32 RecordCount;
|
||||
uint32 FieldCount;
|
||||
uint32 RecordSize;
|
||||
uint32 StringTableSize;
|
||||
uint32 TableHash;
|
||||
uint32 LayoutHash;
|
||||
uint32 MinId;
|
||||
uint32 MaxId;
|
||||
uint32 Locale;
|
||||
uint32 CopyTableSize;
|
||||
uint16 Flags;
|
||||
int16 IndexField;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct TC_SHARED_API DB2LoadInfo
|
||||
struct TC_SHARED_API DB2LoadInfo : public DB2FileLoadInfo
|
||||
{
|
||||
DB2LoadInfo();
|
||||
DB2LoadInfo(DB2FieldMeta const* fields, std::size_t fieldCount, DB2Meta const* meta, HotfixDatabaseStatements statement);
|
||||
|
||||
uint32 GetStringFieldCount(bool localizedOnly) const;
|
||||
|
||||
DB2FieldMeta const* Fields;
|
||||
std::size_t FieldCount;
|
||||
DB2Meta const* Meta;
|
||||
HotfixDatabaseStatements Statement;
|
||||
std::string TypesString;
|
||||
};
|
||||
|
||||
class TC_SHARED_API DB2FileLoader
|
||||
{
|
||||
public:
|
||||
DB2FileLoader();
|
||||
~DB2FileLoader();
|
||||
|
||||
bool Load(char const* filename, DB2LoadInfo const* loadInfo);
|
||||
char* AutoProduceData(uint32& count, char**& indexTable, std::vector<char*>& stringPool);
|
||||
char* AutoProduceStrings(char* dataTable, uint32 locale);
|
||||
void AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable);
|
||||
|
||||
uint32 GetCols() const { return _header.FieldCount; }
|
||||
uint32 GetTableHash() const { return _header.TableHash; }
|
||||
uint32 GetLayoutHash() const { return _header.LayoutHash; }
|
||||
|
||||
private:
|
||||
DB2FileLoaderImpl* _impl;
|
||||
DB2Header _header;
|
||||
};
|
||||
|
||||
class TC_SHARED_API DB2DatabaseLoader
|
||||
File diff suppressed because it is too large
Load Diff
189
src/server/shared/DataStores/DB2Store.cpp
Normal file
189
src/server/shared/DataStores/DB2Store.cpp
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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 "DB2Store.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "DB2DatabaseLoader.h"
|
||||
#include "DB2Meta.h"
|
||||
|
||||
struct DB2FileSystemSource : public DB2FileSource
|
||||
{
|
||||
DB2FileSystemSource(std::string const& fileName)
|
||||
{
|
||||
_fileName = fileName;
|
||||
_file = fopen(_fileName.c_str(), "rb");
|
||||
}
|
||||
|
||||
~DB2FileSystemSource()
|
||||
{
|
||||
if (_file)
|
||||
fclose(_file);
|
||||
}
|
||||
|
||||
bool IsOpen() const override
|
||||
{
|
||||
return _file != nullptr;
|
||||
}
|
||||
|
||||
bool Read(void* buffer, std::size_t numBytes) override
|
||||
{
|
||||
return fread(buffer, numBytes, 1, _file) == 1;
|
||||
}
|
||||
|
||||
std::size_t GetPosition() const override
|
||||
{
|
||||
return ftell(_file);
|
||||
}
|
||||
|
||||
char const* GetFileName() const override
|
||||
{
|
||||
return _fileName.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string _fileName;
|
||||
FILE* _file;
|
||||
};
|
||||
|
||||
DB2StorageBase::DB2StorageBase(char const* fileName, DB2LoadInfo const* loadInfo)
|
||||
: _tableHash(0), _layoutHash(0), _fileName(fileName), _fieldCount(0), _loadInfo(loadInfo), _dataTable(nullptr), _dataTableEx(nullptr), _indexTableSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
DB2StorageBase::~DB2StorageBase()
|
||||
{
|
||||
delete[] _dataTable;
|
||||
delete[] _dataTableEx;
|
||||
for (char* strings : _stringPool)
|
||||
delete[] strings;
|
||||
}
|
||||
|
||||
void DB2StorageBase::WriteRecordData(char const* entry, uint32 locale, ByteBuffer& buffer) const
|
||||
{
|
||||
std::size_t i = 0;
|
||||
if (!_loadInfo->Meta->HasIndexFieldInData())
|
||||
{
|
||||
entry += 4;
|
||||
++i;
|
||||
}
|
||||
|
||||
for (; i < _loadInfo->FieldCount; ++i)
|
||||
{
|
||||
switch (_loadInfo->TypesString[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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DB2StorageBase::Load(std::string const& path, uint32 locale, char**& indexTable)
|
||||
{
|
||||
indexTable = nullptr;
|
||||
DB2FileLoader db2;
|
||||
{
|
||||
DB2FileSystemSource source(path + _fileName);
|
||||
// Check if load was successful, only then continue
|
||||
if (!db2.Load(&source, _loadInfo))
|
||||
return false;
|
||||
}
|
||||
|
||||
_fieldCount = db2.GetCols();
|
||||
_tableHash = db2.GetTableHash();
|
||||
_layoutHash = db2.GetLayoutHash();
|
||||
|
||||
// load raw non-string data
|
||||
_dataTable = db2.AutoProduceData(_indexTableSize, indexTable, _stringPool);
|
||||
|
||||
// load strings from db2 data
|
||||
if (!_stringPool.empty())
|
||||
if (char* stringBlock = db2.AutoProduceStrings(_dataTable, locale))
|
||||
_stringPool.push_back(stringBlock);
|
||||
|
||||
db2.AutoProduceRecordCopies(_indexTableSize, indexTable, _dataTable);
|
||||
|
||||
// error in db2 file at loading if NULL
|
||||
return indexTable != nullptr;
|
||||
}
|
||||
|
||||
bool DB2StorageBase::LoadStringsFrom(std::string const& path, uint32 locale, char** indexTable)
|
||||
{
|
||||
// DB2 must be already loaded using Load
|
||||
if (!indexTable)
|
||||
return false;
|
||||
|
||||
DB2FileLoader db2;
|
||||
{
|
||||
DB2FileSystemSource source(path + _fileName);
|
||||
// Check if load was successful, only then continue
|
||||
if (!db2.Load(&source, _loadInfo))
|
||||
return false;
|
||||
}
|
||||
|
||||
// load strings from another locale db2 data
|
||||
if (_loadInfo->GetStringFieldCount(true))
|
||||
if (char* stringBlock = db2.AutoProduceStrings(_dataTable, locale))
|
||||
_stringPool.push_back(stringBlock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DB2StorageBase::LoadFromDB(char**& indexTable)
|
||||
{
|
||||
char* extraStringHolders = nullptr;
|
||||
_dataTableEx = DB2DatabaseLoader(_fileName, _loadInfo).Load(_indexTableSize, indexTable, extraStringHolders, _stringPool);
|
||||
if (extraStringHolders)
|
||||
_stringPool.push_back(extraStringHolders);
|
||||
}
|
||||
|
||||
void DB2StorageBase::LoadStringsFromDB(uint32 locale, char** indexTable)
|
||||
{
|
||||
if (!_loadInfo->GetStringFieldCount(true))
|
||||
return;
|
||||
|
||||
DB2DatabaseLoader(_fileName, _loadInfo).LoadStrings(locale, _indexTableSize, indexTable, _stringPool);
|
||||
}
|
||||
@@ -19,41 +19,29 @@
|
||||
#define DB2STORE_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "DB2Meta.h"
|
||||
#include "DB2StorageLoader.h"
|
||||
#include "DBStorageIterator.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include <vector>
|
||||
|
||||
class ByteBuffer;
|
||||
struct DB2LoadInfo;
|
||||
|
||||
/// Interface class for common access
|
||||
class DB2StorageBase
|
||||
class TC_SHARED_API DB2StorageBase
|
||||
{
|
||||
public:
|
||||
DB2StorageBase(char const* fileName, DB2LoadInfo&& loadInfo)
|
||||
: _tableHash(0), _layoutHash(0), _fileName(fileName), _fieldCount(0), _loadInfo(std::move(loadInfo)), _dataTable(nullptr), _dataTableEx(nullptr) { }
|
||||
|
||||
virtual ~DB2StorageBase()
|
||||
{
|
||||
delete[] _dataTable;
|
||||
delete[] _dataTableEx;
|
||||
for (char* strings : _stringPool)
|
||||
delete[] strings;
|
||||
}
|
||||
DB2StorageBase(char const* fileName, DB2LoadInfo const* loadInfo);
|
||||
virtual ~DB2StorageBase();
|
||||
|
||||
uint32 GetTableHash() const { return _tableHash; }
|
||||
|
||||
uint32 GetLayoutHash() const { return _layoutHash; }
|
||||
|
||||
virtual bool HasRecord(uint32 id) const = 0;
|
||||
|
||||
virtual void WriteRecord(uint32 id, uint32 locale, ByteBuffer& buffer) const = 0;
|
||||
|
||||
virtual void EraseRecord(uint32 id) = 0;
|
||||
|
||||
std::string const& GetFileName() const { return _fileName; }
|
||||
|
||||
uint32 GetFieldCount() const { return _fieldCount; }
|
||||
|
||||
DB2LoadInfo const* GetLoadInfo() const { return &_loadInfo; }
|
||||
DB2LoadInfo const* GetLoadInfo() const { return _loadInfo; }
|
||||
|
||||
virtual bool Load(std::string const& path, uint32 locale) = 0;
|
||||
virtual bool LoadStringsFrom(std::string const& path, uint32 locale) = 0;
|
||||
@@ -61,63 +49,21 @@ public:
|
||||
virtual void LoadStringsFromDB(uint32 locale) = 0;
|
||||
|
||||
protected:
|
||||
void WriteRecordData(char const* entry, uint32 locale, ByteBuffer& buffer) const
|
||||
{
|
||||
std::size_t i = 0;
|
||||
if (!_loadInfo.Meta->HasIndexFieldInData())
|
||||
{
|
||||
entry += 4;
|
||||
++i;
|
||||
}
|
||||
|
||||
for (; i < _loadInfo.FieldCount; ++i)
|
||||
{
|
||||
switch (_loadInfo.TypesString[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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void WriteRecordData(char const* entry, uint32 locale, ByteBuffer& buffer) const;
|
||||
bool Load(std::string const& path, uint32 locale, char**& indexTable);
|
||||
bool LoadStringsFrom(std::string const& path, uint32 locale, char** indexTable);
|
||||
void LoadFromDB(char**& indexTable);
|
||||
void LoadStringsFromDB(uint32 locale, char** indexTable);
|
||||
|
||||
uint32 _tableHash;
|
||||
uint32 _layoutHash;
|
||||
std::string _fileName;
|
||||
uint32 _fieldCount;
|
||||
DB2LoadInfo _loadInfo;
|
||||
DB2LoadInfo const* _loadInfo;
|
||||
char* _dataTable;
|
||||
char* _dataTableEx;
|
||||
std::vector<char*> _stringPool;
|
||||
uint32 _indexTableSize;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
@@ -128,10 +74,9 @@ class DB2Storage : public DB2StorageBase
|
||||
public:
|
||||
typedef DBStorageIterator<T> iterator;
|
||||
|
||||
DB2Storage(char const* fileName, DB2LoadInfo&& loadInfo) : DB2StorageBase(fileName, std::move(loadInfo)),
|
||||
_indexTableSize(0)
|
||||
DB2Storage(char const* fileName, DB2LoadInfo const* loadInfo) : DB2StorageBase(fileName, loadInfo)
|
||||
{
|
||||
_indexTable.AsT = NULL;
|
||||
_indexTable.AsT = nullptr;
|
||||
}
|
||||
|
||||
~DB2Storage()
|
||||
@@ -153,61 +98,22 @@ public:
|
||||
uint32 GetNumRows() const { return _indexTableSize; }
|
||||
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(), &_loadInfo))
|
||||
return false;
|
||||
|
||||
_fieldCount = db2.GetCols();
|
||||
_tableHash = db2.GetTableHash();
|
||||
_layoutHash = db2.GetLayoutHash();
|
||||
|
||||
// load raw non-string data
|
||||
_dataTable = db2.AutoProduceData(_indexTableSize, _indexTable.AsChar, _stringPool);
|
||||
|
||||
// load strings from db2 data
|
||||
if (!_stringPool.empty())
|
||||
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;
|
||||
return DB2StorageBase::Load(path, locale, _indexTable.AsChar);
|
||||
}
|
||||
|
||||
bool LoadStringsFrom(std::string const& path, uint32 locale) override
|
||||
{
|
||||
// DB2 must be already loaded using Load
|
||||
if (!_indexTable.AsT)
|
||||
return false;
|
||||
|
||||
DB2FileLoader db2;
|
||||
// Check if load was successful, only then continue
|
||||
if (!db2.Load((path + _fileName).c_str(), &_loadInfo))
|
||||
return false;
|
||||
|
||||
// load strings from another locale db2 data
|
||||
if (_loadInfo.GetStringFieldCount(true))
|
||||
if (char* stringBlock = db2.AutoProduceStrings(_dataTable, locale))
|
||||
_stringPool.push_back(stringBlock);
|
||||
return true;
|
||||
return DB2StorageBase::LoadStringsFrom(path, locale, _indexTable.AsChar);
|
||||
}
|
||||
|
||||
void LoadFromDB() override
|
||||
{
|
||||
char* extraStringHolders = nullptr;
|
||||
_dataTableEx = DB2DatabaseLoader(_fileName, &_loadInfo).Load(_indexTableSize, _indexTable.AsChar, extraStringHolders, _stringPool);
|
||||
if (extraStringHolders)
|
||||
_stringPool.push_back(extraStringHolders);
|
||||
DB2StorageBase::LoadFromDB(_indexTable.AsChar);
|
||||
}
|
||||
|
||||
void LoadStringsFromDB(uint32 locale) override
|
||||
{
|
||||
if (!_loadInfo.GetStringFieldCount(true))
|
||||
return;
|
||||
|
||||
DB2DatabaseLoader(_fileName, &_loadInfo).LoadStrings(locale, _indexTableSize, _indexTable.AsChar, _stringPool);
|
||||
DB2StorageBase::LoadStringsFromDB(locale, _indexTable.AsChar);
|
||||
}
|
||||
|
||||
iterator begin() { return iterator(_indexTable.AsT, _indexTableSize); }
|
||||
@@ -219,7 +125,6 @@ private:
|
||||
T** AsT;
|
||||
char** AsChar;
|
||||
} _indexTable;
|
||||
uint32 _indexTableSize;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user