TrinityCore
DB2DatabaseLoader.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "DB2DatabaseLoader.h"
19#include "Common.h"
20#include "DatabaseEnv.h"
21#include "DB2Meta.h"
22#include "Errors.h"
23#include "Log.h"
24#include <cstring>
25
26static char const* nullStr = "";
27
28char* DB2DatabaseLoader::Load(bool custom, uint32& records, char**& indexTable, std::vector<char*>& stringPool, uint32& minId)
29{
30 // Even though this query is executed only once, prepared statement is used to send data from mysql server in binary format
32 stmt->setBool(0, !custom);
33 PreparedQueryResult result = HotfixDatabase.Query(stmt);
34 if (!result)
35 return nullptr;
36
37 if (_loadInfo->Meta->GetDbFieldCount() != result->GetFieldCount())
38 return nullptr;
39
40 // get struct size and index pos
41 uint32 indexField = _loadInfo->Meta->GetDbIndexField();
42 uint32 recordSize = _loadInfo->Meta->GetRecordSize();
43
44 // we store flat holders pool as single memory block
45 std::size_t stringFields = _loadInfo->GetStringFieldCount(false);
46
47 // Resize index table
48 uint32 indexTableSize = records;
50 if (uint32((*maxIdResult)[0].GetUInt64()) > records)
51 indexTableSize = uint32((*maxIdResult)[0].GetUInt64());
52
53 if (indexTableSize > records)
54 {
55 char** tmpIdxTable = new char*[indexTableSize];
56 memset(tmpIdxTable, 0, indexTableSize * sizeof(char*));
57 memcpy(tmpIdxTable, indexTable, records * sizeof(char*));
58 delete[] indexTable;
59 indexTable = tmpIdxTable;
60 }
61
62 char* tempDataTable = new char[result->GetRowCount() * recordSize];
63 memset(tempDataTable, 0, result->GetRowCount() * recordSize);
64 uint32* newIndexes = new uint32[result->GetRowCount()];
65 if (stringFields)
66 stringPool.reserve(std::max<uint64>(stringPool.capacity(), stringPool.size() + stringFields * result->GetRowCount() + 1));
67
68 uint32 newRecords = 0;
69
70 do
71 {
72 Field* fields = result->Fetch();
73 uint32 offset = 0;
74
75 uint32 indexValue = fields[indexField].GetUInt32();
76 bool isNew = false;
77
78 // Attempt to overwrite existing data
79 char* dataValue = indexTable[indexValue];
80 if (!dataValue)
81 {
82 newIndexes[newRecords] = indexValue;
83 dataValue = &tempDataTable[newRecords++ * recordSize];
84 isNew = true;
85 }
86
87 uint32 f = 0;
89 {
90 *((uint32*)(&dataValue[offset])) = indexValue;
91 offset += 4;
92 ++f;
93 }
94
95 for (uint32 x = 0; x < _loadInfo->Meta->FieldCount; ++x)
96 {
97 for (uint32 z = 0; z < _loadInfo->Meta->Fields[x].ArraySize; ++z)
98 {
99 switch (_loadInfo->Fields[f].Type)
100 {
101 case FT_FLOAT:
102 *((float*)(&dataValue[offset])) = fields[f].GetFloat();
103 offset += 4;
104 break;
105 case FT_INT:
106 *((int32*)(&dataValue[offset])) = fields[f].GetInt32();
107 offset += 4;
108 break;
109 case FT_BYTE:
110 *((int8*)(&dataValue[offset])) = fields[f].GetInt8();
111 offset += 1;
112 break;
113 case FT_SHORT:
114 *((int16*)(&dataValue[offset])) = fields[f].GetInt16();
115 offset += 2;
116 break;
117 case FT_LONG:
118 *((int64*)(&dataValue[offset])) = fields[f].GetInt64();
119 offset += 8;
120 break;
121 case FT_STRING:
122 {
123 LocalizedString* slot = (LocalizedString*)(&dataValue[offset]);
124 if (isNew)
125 for (char const*& localeStr : slot->Str)
126 localeStr = nullStr;
127
128 // Value in database in main table field must be for enUS locale
129 if (char* str = AddString(&slot->Str[LOCALE_enUS], fields[f].GetString()))
130 stringPool.push_back(str);
131
132 offset += sizeof(LocalizedString);
133 break;
134 }
136 {
137 char const** slot = (char const**)(&dataValue[offset]);
138
139 // Value in database in main table field must be for enUS locale
140 if (char* str = AddString(slot, fields[f].GetString()))
141 stringPool.push_back(str);
142 else
143 *slot = nullStr;
144
145 offset += sizeof(char*);
146 break;
147 }
148 default:
149 ABORT_MSG("Unknown format character '%c' found in %s meta for field %s",
151 break;
152 }
153 ++f;
154 }
155 }
156
157 ASSERT(offset == recordSize);
158 } while (result->NextRow());
159
160 if (!newRecords)
161 {
162 delete[] tempDataTable;
163 delete[] newIndexes;
164 return nullptr;
165 }
166
167 // Compact new data table to only contain new records not previously loaded from file
168 char* dataTable = new char[newRecords * recordSize];
169 memcpy(dataTable, tempDataTable, newRecords * recordSize);
170
171 // insert new records to index table
172 for (uint32 i = 0; i < newRecords; ++i)
173 {
174 uint32 newId = newIndexes[i];
175 indexTable[newId] = &dataTable[i * recordSize];
176 minId = std::min(minId, newId);
177 }
178
179 delete[] tempDataTable;
180 delete[] newIndexes;
181
182 records = indexTableSize;
183
184 return dataTable;
185}
186
187void DB2DatabaseLoader::LoadStrings(bool custom, LocaleConstant locale, uint32 records, char** indexTable, std::vector<char*>& stringPool)
188{
190 stmt->setBool(0, !custom);
191 stmt->setString(1, localeNames[locale]);
192 PreparedQueryResult result = HotfixDatabase.Query(stmt);
193 if (!result)
194 return;
195
196 std::size_t stringFields = _loadInfo->GetStringFieldCount(true);
197 if (result->GetFieldCount() != stringFields + 1 /*ID*/)
198 return;
199
200 uint32 fieldCount = _loadInfo->Meta->FieldCount;
201 uint32 recordSize = _loadInfo->Meta->GetRecordSize();
202
203 stringPool.reserve(std::max<uint64>(stringPool.capacity(), stringPool.size() + stringFields * result->GetRowCount() + 1));
204
205 do
206 {
207 Field* fields = result->Fetch();
208 uint32 offset = 0;
209 uint32 stringFieldNumInRecord = 0;
210 uint32 indexValue = fields[0].GetUInt32();
211
212 if (indexValue >= records)
213 continue;
214
215 // Attempt to overwrite existing data
216 if (char* dataValue = indexTable[indexValue])
217 {
218 uint32 fieldIndex = 0;
220 {
221 offset += 4;
222 ++fieldIndex;
223 }
224
225 for (uint32 x = 0; x < fieldCount; ++x)
226 {
227 for (uint32 z = 0; z < _loadInfo->Meta->Fields[x].ArraySize; ++z)
228 {
229 switch (_loadInfo->Fields[fieldIndex].Type)
230 {
231 case FT_FLOAT:
232 case FT_INT:
233 offset += 4;
234 break;
235 case FT_BYTE:
236 offset += 1;
237 break;
238 case FT_SHORT:
239 offset += 2;
240 break;
241 case FT_LONG:
242 offset += 8;
243 break;
244 case FT_STRING:
245 {
246 // fill only not filled entries
247 LocalizedString* db2str = (LocalizedString*)(&dataValue[offset]);
248 if (char* str = AddString(&db2str->Str[locale], fields[1 + stringFieldNumInRecord].GetString()))
249 stringPool.push_back(str);
250
251 ++stringFieldNumInRecord;
252 offset += sizeof(LocalizedString);
253 break;
254 }
256 offset += sizeof(char*);
257 break;
258 default:
259 ABORT_MSG("Unknown format character '%c' found in %s meta for field %s",
260 _loadInfo->Fields[fieldIndex].Type, _storageName.c_str(), _loadInfo->Fields[fieldIndex].Name);
261 break;
262 }
263 ++fieldIndex;
264 }
265 }
266
267 ASSERT(offset == recordSize);
268 }
269 else
270 TC_LOG_ERROR("sql.sql", "Hotfix locale table for storage {} references row that does not exist {} locale {}!", _storageName, indexValue, localeNames[locale]);
271
272 } while (result->NextRow());
273}
274
275char* DB2DatabaseLoader::AddString(char const** holder, std::string const& value)
276{
277 if (!value.empty())
278 {
279 char* str = new char[value.length() + 1];
280 memcpy(str, value.c_str(), value.length());
281 str[value.length()] = '\0';
282 *holder = str;
283 return str;
284 }
285
286 return nullptr;
287}
char const * localeNames[TOTAL_LOCALES]
Definition: Common.cpp:20
LocaleConstant
Definition: Common.h:48
@ LOCALE_enUS
Definition: Common.h:49
static char const * nullStr
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< HotfixDatabaseConnection > HotfixDatabase
Accessor to the hotfix database.
Definition: DatabaseEnv.cpp:23
int64_t int64
Definition: Define.h:137
int16_t int16
Definition: Define.h:139
int8_t int8
Definition: Define.h:140
int32_t int32
Definition: Define.h:138
@ FT_FLOAT
Definition: Define.h:150
@ FT_SHORT
Definition: Define.h:153
@ FT_STRING
Definition: Define.h:148
@ FT_INT
Definition: Define.h:151
@ FT_STRING_NOT_LOCALIZED
Definition: Define.h:149
@ FT_BYTE
Definition: Define.h:152
@ FT_LONG
Definition: Define.h:154
uint32_t uint32
Definition: Define.h:142
#define ABORT_MSG
Definition: Errors.h:75
#define ASSERT
Definition: Errors.h:68
HotfixDatabaseStatements
uint32 constexpr HOTFIX_MAX_ID_STMT_OFFSET
uint32 constexpr HOTFIX_LOCALE_STMT_OFFSET
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
char * Load(bool custom, uint32 &records, char **&indexTable, std::vector< char * > &stringPool, uint32 &minId)
DB2LoadInfo const * _loadInfo
void LoadStrings(bool custom, LocaleConstant locale, uint32 records, char **indexTable, std::vector< char * > &stringPool)
std::string const & _storageName
static char * AddString(char const **holder, std::string const &value)
Class used to access individual fields of database query result.
Definition: Field.h:90
std::string GetString() const
Definition: Field.cpp:118
uint32 GetUInt32() const
Definition: Field.cpp:62
void setBool(const uint8 index, const bool value)
void setString(const uint8 index, const std::string &value)
char const * Name
Definition: DB2FileLoader.h:77
DBCFormer Type
Definition: DB2FileLoader.h:76
DB2Meta const * Meta
Definition: DB2FileLoader.h:91
uint32 GetStringFieldCount(bool localizedOnly) const
DB2FieldMeta const * Fields
Definition: DB2FileLoader.h:89
HotfixDatabaseStatements Statement
uint8 ArraySize
Definition: DB2Meta.h:26
uint32 GetDbIndexField() const
Definition: DB2Meta.cpp:171
DB2MetaField const * Fields
Definition: DB2Meta.h:60
uint32 GetDbFieldCount() const
Definition: DB2Meta.cpp:183
uint32 GetRecordSize() const
Definition: DB2Meta.cpp:32
bool HasIndexFieldInData() const
Definition: DB2Meta.cpp:22
uint32 FieldCount
Definition: DB2Meta.h:57
std::array< char const *, TOTAL_LOCALES > Str
Definition: Common.h:109