TrinityCore
DB2FileLoader.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 "DB2FileLoader.h"
19#include "ByteConverter.h"
20#include "DB2Meta.h"
21#include "Errors.h"
22#include "Log.h"
23#include <limits>
24#include <sstream>
25#include <system_error>
26#include <utility>
27#include <cstring>
28
30{
31 None,
34 Pallet,
37};
38
39#pragma pack(push, 1)
40
42{
45};
46
48{
51};
52
54{
59 union
60 {
61 struct
62 {
65 bool Signed;
67
68 struct
69 {
72
73 struct
74 {
80};
81
83{
86};
87
89{
91};
92
94{
98};
99
101{
104};
105
106#pragma pack(pop)
107
109{
110 std::vector<DB2IndexEntry> Entries;
111};
112
113static bool IsKnownTactId(uint64 tactId)
114{
115 return tactId == 0 || tactId == DUMMY_KNOWN_TACT_ID;
116}
117
119{
120 uint32 stringFields = 0;
121 for (std::size_t i = 0; i < FieldCount; ++i)
122 if (Fields[i].Type == FT_STRING || (Fields[i].Type == FT_STRING_NOT_LOCALIZED && !localizedOnly))
123 ++stringFields;
124
125 return stringFields;
126}
127
128std::pair<int32, int32> DB2FileLoadInfo::GetFieldIndexByName(char const* fieldName) const
129{
130 std::size_t ourIndex = Meta->HasIndexFieldInData() ? 0 : 1;
131 for (uint32 i = 0; i < Meta->FieldCount; ++i)
132 {
133 for (uint8 arr = 0; arr < Meta->Fields[i].ArraySize; ++arr)
134 {
135 if (!strcmp(Fields[ourIndex].Name, fieldName))
136 return std::make_pair(int32(i), int32(arr));
137
138 ++ourIndex;
139 }
140 }
141
142 return std::make_pair(-1, -1);
143}
144
146{
147 ASSERT(metaIndex < Meta->FieldCount);
148 int32 ourIndex = Meta->HasIndexFieldInData() ? 0 : 1;
149 for (uint32 i = 0; i < metaIndex; ++i)
150 ourIndex += Meta->Fields[i].ArraySize;
151
152 return ourIndex;
153}
154
157
159{
160public:
161 DB2FileLoaderImpl() = default;
162 DB2FileLoaderImpl(DB2FileLoaderImpl const& other) = delete;
163 DB2FileLoaderImpl(DB2FileLoaderImpl&& other) noexcept = delete;
165 DB2FileLoaderImpl& operator=(DB2FileLoaderImpl&& other) noexcept = delete;
166 virtual ~DB2FileLoaderImpl() = default;
167 virtual void LoadColumnData(std::unique_ptr<DB2SectionHeader[]> sections, std::unique_ptr<DB2FieldEntry[]> fields, std::unique_ptr<DB2ColumnMeta[]> columnMeta,
168 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletValues, std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletArrayValues,
169 std::unique_ptr<std::unordered_map<uint32, uint32>[]> commonValues) = 0;
170 virtual void SkipEncryptedSection(uint32 section) = 0;
171 virtual bool LoadTableData(DB2FileSource* source, uint32 section) = 0;
172 virtual bool LoadCatalogData(DB2FileSource* source, uint32 section) = 0;
173 virtual void SetAdditionalData(std::vector<uint32> idTable, std::vector<DB2RecordCopy> copyTable, std::vector<std::vector<DB2IndexData>> parentIndexes) = 0;
174 virtual char* AutoProduceData(uint32& indexTableSize, char**& indexTable) = 0;
175 virtual char* AutoProduceStrings(char** indexTable, uint32 indexTableSize, uint32 locale) = 0;
176 virtual void AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable) = 0;
177 virtual DB2Record GetRecord(uint32 recordNumber) const = 0;
178 virtual DB2RecordCopy GetRecordCopy(uint32 copyNumber) const = 0;
179 virtual uint32 GetRecordCount() const = 0;
180 virtual uint32 GetRecordCopyCount() const = 0;
181 virtual uint32 GetMinId() const = 0;
182 virtual uint32 GetMaxId() const = 0;
183 virtual DB2FileLoadInfo const* GetLoadInfo() const = 0;
184 virtual DB2SectionHeader& GetSection(uint32 section) const = 0;
185 virtual bool IsSignedField(uint32 field) const = 0;
186 virtual char const* GetExpectedSignMismatchReason(uint32 field) const = 0;
187
188private:
189 friend class DB2Record;
190 virtual unsigned char const* GetRawRecordData(uint32 recordNumber, uint32 const* section) const = 0;
191 virtual uint32 RecordGetId(uint8 const* record, uint32 recordIndex) const = 0;
192 virtual uint8 RecordGetUInt8(uint8 const* record, uint32 field, uint32 arrayIndex) const = 0;
193 virtual uint16 RecordGetUInt16(uint8 const* record, uint32 field, uint32 arrayIndex) const = 0;
194 virtual uint32 RecordGetUInt32(uint8 const* record, uint32 field, uint32 arrayIndex) const = 0;
195 virtual int32 RecordGetInt32(uint8 const* record, uint32 field, uint32 arrayIndex) const = 0;
196 virtual uint64 RecordGetUInt64(uint8 const* record, uint32 field, uint32 arrayIndex) const = 0;
197 virtual float RecordGetFloat(uint8 const* record, uint32 field, uint32 arrayIndex) const = 0;
198 virtual char const* RecordGetString(uint8 const* record, uint32 field, uint32 arrayIndex) const = 0;
199 virtual std::size_t* RecordCreateDetachedFieldOffsets(std::size_t* oldOffsets) const = 0;
200 virtual std::size_t* RecordCopyDetachedFieldOffsets(std::size_t* oldOffsets) const = 0;
201 virtual void RecordDestroyFieldOffsets(std::size_t*& fieldOffsets) const = 0;
202};
203
205{
206public:
207 DB2FileLoaderRegularImpl(char const* fileName, DB2FileLoadInfo const* loadInfo, DB2Header const* header);
213
214 void LoadColumnData(std::unique_ptr<DB2SectionHeader[]> sections, std::unique_ptr<DB2FieldEntry[]> fields, std::unique_ptr<DB2ColumnMeta[]> columnMeta,
215 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletValues, std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletArrayValues,
216 std::unique_ptr<std::unordered_map<uint32, uint32>[]> commonValues) override;
217 void SkipEncryptedSection(uint32 /*section*/) override { }
218 bool LoadTableData(DB2FileSource* source, uint32 section) override;
219 bool LoadCatalogData(DB2FileSource* /*source*/, uint32 /*section*/) override { return true; }
220 void SetAdditionalData(std::vector<uint32> idTable, std::vector<DB2RecordCopy> copyTable, std::vector<std::vector<DB2IndexData>> parentIndexes) override;
221 char* AutoProduceData(uint32& indexTableSize, char**& indexTable) override;
222 char* AutoProduceStrings(char** indexTable, uint32 indexTableSize, uint32 locale) override;
223 void AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable) override;
224 DB2Record GetRecord(uint32 recordNumber) const override;
225 DB2RecordCopy GetRecordCopy(uint32 copyNumber) const override;
226 uint32 GetRecordCount() const override;
227 uint32 GetRecordCopyCount() const override;
228 uint32 GetMinId() const override;
229 uint32 GetMaxId() const override;
230 DB2FileLoadInfo const* GetLoadInfo() const override;
231 DB2SectionHeader& GetSection(uint32 section) const override;
232 bool IsSignedField(uint32 field) const override;
233 char const* GetExpectedSignMismatchReason(uint32 field) const override;
234
235private:
236 void FillParentLookup(char* dataTable);
237 uint32 GetRecordSection(uint32 recordNumber) const;
238 unsigned char const* GetRawRecordData(uint32 recordNumber, uint32 const* section) const override;
239 uint32 RecordGetId(uint8 const* record, uint32 recordIndex) const override;
240 uint8 RecordGetUInt8(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
241 uint16 RecordGetUInt16(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
242 uint32 RecordGetUInt32(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
243 int32 RecordGetInt32(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
244 uint64 RecordGetUInt64(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
245 float RecordGetFloat(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
246 char const* RecordGetString(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
247 template<typename T>
248 T RecordGetVarInt(uint8 const* record, uint32 field, uint32 arrayIndex) const;
249 uint64 RecordGetPackedValue(uint8 const* packedRecordData, uint32 bitWidth, uint32 bitOffset) const;
250 uint16 GetFieldOffset(uint32 field) const;
251 std::size_t* RecordCreateDetachedFieldOffsets(std::size_t* oldOffsets) const override;
252 std::size_t* RecordCopyDetachedFieldOffsets(std::size_t* oldOffsets) const override;
253 void RecordDestroyFieldOffsets(std::size_t*& fieldOffsets) const override;
254
255 char const* _fileName;
258 std::unique_ptr<uint8[]> _data;
260 std::unique_ptr<DB2SectionHeader[]> _sections;
261 std::unique_ptr<DB2ColumnMeta[]> _columnMeta;
262 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> _palletValues;
263 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> _palletArrayValues;
264 std::unique_ptr<std::unordered_map<uint32, uint32>[]> _commonValues;
265 std::vector<uint32> _idTable;
266 std::vector<DB2RecordCopy> _copyTable;
267 std::vector<std::vector<DB2IndexData>> _parentIndexes;
268};
269
271{
272public:
273 DB2FileLoaderSparseImpl(char const* fileName, DB2FileLoadInfo const* loadInfo, DB2Header const* header, DB2FileSource* source);
279
280 void LoadColumnData(std::unique_ptr<DB2SectionHeader[]> sections, std::unique_ptr<DB2FieldEntry[]> fields, std::unique_ptr<DB2ColumnMeta[]> columnMeta,
281 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletValues, std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletArrayValues,
282 std::unique_ptr<std::unordered_map<uint32, uint32>[]> commonValues) override;
283 void SkipEncryptedSection(uint32 section) override;
284 bool LoadTableData(DB2FileSource* /*source*/, uint32 /*section*/) override { return true; }
285 bool LoadCatalogData(DB2FileSource* source, uint32 section) override;
286 void SetAdditionalData(std::vector<uint32> idTable, std::vector<DB2RecordCopy> copyTable, std::vector<std::vector<DB2IndexData>> parentIndexes) override;
287 char* AutoProduceData(uint32& indexTableSize, char**& indexTable) override;
288 char* AutoProduceStrings(char** indexTable, uint32 indexTableSize, uint32 locale) override;
289 void AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable) override;
290 DB2Record GetRecord(uint32 recordNumber) const override;
291 DB2RecordCopy GetRecordCopy(uint32 copyNumber) const override;
292 uint32 GetRecordCount() const override;
293 uint32 GetRecordCopyCount() const override;
294 uint32 GetMinId() const override;
295 uint32 GetMaxId() const override;
296 DB2FileLoadInfo const* GetLoadInfo() const override;
297 DB2SectionHeader& GetSection(uint32 section) const override;
298 bool IsSignedField(uint32 field) const override;
299 char const* GetExpectedSignMismatchReason(uint32 field) const override;
300
301private:
302 void FillParentLookup(char* dataTable);
303 uint32 GetRecordSection(uint32 recordNumber) const;
304 unsigned char const* GetRawRecordData(uint32 recordNumber, uint32 const* section) const override;
305 uint32 RecordGetId(uint8 const* record, uint32 recordIndex) const override;
306 uint8 RecordGetUInt8(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
307 uint16 RecordGetUInt16(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
308 uint32 RecordGetUInt32(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
309 int32 RecordGetInt32(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
310 uint64 RecordGetUInt64(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
311 float RecordGetFloat(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
312 char const* RecordGetString(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
313 uint32 RecordGetVarInt(uint8 const* record, uint32 field, uint32 arrayIndex, bool isSigned) const;
314 uint16 GetFieldOffset(uint32 field, uint32 arrayIndex) const;
315 uint16 GetFieldSize(uint32 field) const;
316 std::size_t* RecordCreateDetachedFieldOffsets(std::size_t* oldOffsets) const override;
317 std::size_t* RecordCopyDetachedFieldOffsets(std::size_t* oldOffsets) const override;
318 void RecordDestroyFieldOffsets(std::size_t*& fieldOffsets) const override;
319 void CalculateAndStoreFieldOffsets(uint8 const* rawRecord) const;
320
321 char const* _fileName;
325 std::size_t _totalRecordSize;
327 std::unique_ptr<uint8[]> _recordBuffer;
328 std::unique_ptr<DB2SectionHeader[]> _sections;
329 std::unique_ptr<DB2FieldEntry[]> _fields;
330 std::unique_ptr<std::size_t[]> _fieldAndArrayOffsets;
331 std::vector<uint32> _catalogIds;
332 std::vector<DB2CatalogEntry> _catalog;
333 std::vector<DB2RecordCopy> _copyTable;
334 std::vector<std::vector<DB2IndexData>> _parentIndexes;
335};
336
337DB2FileLoaderRegularImpl::DB2FileLoaderRegularImpl(char const* fileName, DB2FileLoadInfo const* loadInfo, DB2Header const* header) :
338 _fileName(fileName),
339 _loadInfo(loadInfo),
340 _header(header),
341 _stringTable(nullptr)
342{
343}
344
345void DB2FileLoaderRegularImpl::LoadColumnData(std::unique_ptr<DB2SectionHeader[]> sections, std::unique_ptr<DB2FieldEntry[]> /*fields*/, std::unique_ptr<DB2ColumnMeta[]> columnMeta,
346 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletValues, std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletArrayValues,
347 std::unique_ptr<std::unordered_map<uint32, uint32>[]> commonValues)
348{
349 _sections = std::move(sections);
350 _columnMeta = std::move(columnMeta);
351 _palletValues = std::move(palletValues);
352 _palletArrayValues = std::move(palletArrayValues);
353 _commonValues = std::move(commonValues);
354}
355
357{
358 if (!_data)
359 {
360 _data = std::make_unique<uint8[]>(_header->RecordSize * _header->RecordCount + _header->StringTableSize + 8);
362 }
363
364 uint32 sectionDataStart = 0;
365 uint32 sectionStringTableStart = 0;
366 for (uint32 i = 0; i < section; ++i)
367 {
368 sectionDataStart += _header->RecordSize * _sections[i].RecordCount;
369 sectionStringTableStart += _sections[i].StringTableSize;
370 }
371
372 if (_sections[section].RecordCount && !source->Read(&_data[sectionDataStart], _header->RecordSize * _sections[section].RecordCount))
373 return false;
374
375 if (_sections[section].StringTableSize && !source->Read(&_stringTable[sectionStringTableStart], _sections[section].StringTableSize))
376 return false;
377
378 return true;
379}
380
381void DB2FileLoaderRegularImpl::SetAdditionalData(std::vector<uint32> idTable, std::vector<DB2RecordCopy> copyTable, std::vector<std::vector<DB2IndexData>> parentIndexes)
382{
383 _idTable = std::move(idTable);
384 _copyTable = std::move(copyTable);
385 _parentIndexes = std::move(parentIndexes);
386}
387
389
390static char const* const EmptyDb2String = "";
391
392char* DB2FileLoaderRegularImpl::AutoProduceData(uint32& indexTableSize, char**& indexTable)
393{
394 //get struct size and index pos
395 uint32 recordsize = _loadInfo->Meta->GetRecordSize();
396
397 uint32 maxi = GetMaxId() + 1;
398
399 using index_entry_t = char*;
400
401 indexTableSize = maxi;
402 indexTable = new index_entry_t[maxi];
403 memset(indexTable, 0, maxi * sizeof(index_entry_t));
404
405 char* dataTable = new char[(_header->RecordCount + _copyTable.size()) * recordsize];
406
407 uint32 offset = 0;
408 uint32 recordIndex = 0;
409
410 for (uint32 section = 0; section < _header->SectionCount; ++section)
411 {
412 DB2SectionHeader const& sectionHeader = GetSection(section);
413 if (!IsKnownTactId(sectionHeader.TactId))
414 {
415 offset += recordsize * sectionHeader.RecordCount;
416 recordIndex += sectionHeader.RecordCount;
417 continue;
418 }
419
420 for (uint32 sr = 0; sr < sectionHeader.RecordCount; ++sr, ++recordIndex)
421 {
422 unsigned char const* rawRecord = GetRawRecordData(recordIndex, &section);
423 if (!rawRecord)
424 continue;
425
426 uint32 indexVal = RecordGetId(rawRecord, recordIndex);
427
428 indexTable[indexVal] = &dataTable[offset];
429
430 uint32 fieldIndex = 0;
432 {
433 *reinterpret_cast<uint32*>(&dataTable[offset]) = indexVal;
434 offset += 4;
435 ++fieldIndex;
436 }
437
438 for (uint32 x = 0; x < _header->FieldCount; ++x)
439 {
440 for (uint32 z = 0; z < _loadInfo->Meta->Fields[x].ArraySize; ++z)
441 {
442 switch (_loadInfo->Fields[fieldIndex].Type)
443 {
444 case FT_FLOAT:
445 *reinterpret_cast<float*>(&dataTable[offset]) = RecordGetFloat(rawRecord, x, z);
446 offset += 4;
447 break;
448 case FT_INT:
449 *reinterpret_cast<uint32*>(&dataTable[offset]) = RecordGetVarInt<uint32>(rawRecord, x, z);
450 offset += 4;
451 break;
452 case FT_BYTE:
453 *reinterpret_cast<uint8*>(&dataTable[offset]) = RecordGetUInt8(rawRecord, x, z);
454 offset += 1;
455 break;
456 case FT_SHORT:
457 *reinterpret_cast<uint16*>(&dataTable[offset]) = RecordGetUInt16(rawRecord, x, z);
458 offset += 2;
459 break;
460 case FT_LONG:
461 *reinterpret_cast<uint64*>(&dataTable[offset]) = RecordGetUInt64(rawRecord, x, z);
462 offset += 8;
463 break;
464 case FT_STRING:
465 for (char const*& localeStr : reinterpret_cast<LocalizedString*>(&dataTable[offset])->Str)
466 localeStr = EmptyDb2String;
467
468 offset += sizeof(LocalizedString);
469 break;
471 *reinterpret_cast<char const**>(&dataTable[offset]) = EmptyDb2String;
472 offset += sizeof(char*);
473 break;
474 default:
475 ABORT_MSG("Unknown format character '%c' found in %s meta for field %s",
476 _loadInfo->Fields[fieldIndex].Type, _fileName, _loadInfo->Fields[fieldIndex].Name);
477 break;
478 }
479 ++fieldIndex;
480 }
481 }
482
483 for (uint32 x = _header->FieldCount; x < _loadInfo->Meta->FieldCount; ++x)
484 {
485 for (uint32 z = 0; z < _loadInfo->Meta->Fields[x].ArraySize; ++z)
486 {
487 switch (_loadInfo->Fields[fieldIndex].Type)
488 {
489 case FT_INT:
490 *reinterpret_cast<uint32*>(&dataTable[offset]) = 0;
491 offset += 4;
492 break;
493 case FT_BYTE:
494 *reinterpret_cast<uint8*>(&dataTable[offset]) = 0;
495 offset += 1;
496 break;
497 case FT_SHORT:
498 *reinterpret_cast<uint16*>(&dataTable[offset]) = 0;
499 offset += 2;
500 break;
501 default:
502 ABORT_MSG("Unknown format character '%c' found in %s meta for parent field %s",
503 _loadInfo->Fields[fieldIndex].Type, _fileName, _loadInfo->Fields[fieldIndex].Name);
504 break;
505 }
506 ++fieldIndex;
507 }
508 }
509 }
510 }
511
512 if (!_parentIndexes.empty())
513 FillParentLookup(dataTable);
514
515 return dataTable;
516}
517
518char* DB2FileLoaderRegularImpl::AutoProduceStrings(char** indexTable, uint32 indexTableSize, uint32 locale)
519{
520 if (!(_header->Locale & (1 << locale)))
521 {
522 char const* sep = "";
523 std::ostringstream str;
524 for (uint32 i = 0; i < TOTAL_LOCALES; ++i)
525 {
526 if (_header->Locale & (1 << i))
527 {
528 str << sep << localeNames[i];
529 sep = ", ";
530 }
531 }
532
533 TC_LOG_ERROR("", "Attempted to load {} which has locales {} as {}. Check if you placed your localized db2 files in correct directory.", _fileName, str.str(), localeNames[locale]);
534 return nullptr;
535 }
536
537 if (!_loadInfo->GetStringFieldCount(false))
538 return nullptr;
539
540 char* stringPool = new char[_header->StringTableSize];
541 memcpy(stringPool, _stringTable, _header->StringTableSize);
542
543 uint32 y = 0;
544
545 for (uint32 section = 0; section < _header->SectionCount; ++section)
546 {
547 DB2SectionHeader const& sectionHeader = GetSection(section);
548 if (!IsKnownTactId(sectionHeader.TactId))
549 {
550 y += sectionHeader.RecordCount;
551 continue;
552 }
553
554 for (uint32 sr = 0; sr < sectionHeader.RecordCount; ++sr, ++y)
555 {
556 unsigned char const* rawRecord = GetRawRecordData(y, &section);
557 if (!rawRecord)
558 continue;
559
560 uint32 indexVal = RecordGetId(rawRecord, y);
561 if (indexVal >= indexTableSize)
562 continue;
563
564 char* recordData = indexTable[indexVal];
565 if (!recordData)
566 continue;
567
568 uint32 offset = 0;
569 uint32 fieldIndex = 0;
571 {
572 offset += 4;
573 ++fieldIndex;
574 }
575
576 for (uint32 x = 0; x < _loadInfo->Meta->FieldCount; ++x)
577 {
578 for (uint32 z = 0; z < _loadInfo->Meta->Fields[x].ArraySize; ++z)
579 {
580 switch (_loadInfo->Fields[fieldIndex].Type)
581 {
582 case FT_FLOAT:
583 case FT_INT:
584 offset += 4;
585 break;
586 case FT_BYTE:
587 offset += 1;
588 break;
589 case FT_SHORT:
590 offset += 2;
591 break;
592 case FT_LONG:
593 offset += 8;
594 break;
595 case FT_STRING:
596 if (char const* string = RecordGetString(rawRecord, x, z))
597 reinterpret_cast<LocalizedString*>(&recordData[offset])->Str[locale] = stringPool + (string - reinterpret_cast<char const*>(_stringTable));
598
599 offset += sizeof(LocalizedString);
600 break;
602 if (char const* string = RecordGetString(rawRecord, x, z))
603 *reinterpret_cast<char**>(&recordData[offset]) = stringPool + (string - reinterpret_cast<char const*>(_stringTable));
604
605 offset += sizeof(char*);
606 break;
607 default:
608 ABORT_MSG("Unknown format character '%c' found in %s meta for field %s",
609 _loadInfo->Fields[fieldIndex].Type, _fileName, _loadInfo->Fields[fieldIndex].Name);
610 break;
611 }
612 ++fieldIndex;
613 }
614 }
615 }
616 }
617
618 return stringPool;
619}
620
621void DB2FileLoaderRegularImpl::AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable)
622{
623 uint32 recordCopies = GetRecordCopyCount();
624 if (!recordCopies)
625 return;
626
627 uint32 recordsize = _loadInfo->Meta->GetRecordSize();
628 uint32 offset = _header->RecordCount * recordsize;
630 for (uint32 c = 0; c < recordCopies; ++c)
631 {
633 if (copy.SourceRowId && copy.SourceRowId < records && copy.NewRowId < records && indexTable[copy.SourceRowId])
634 {
635 indexTable[copy.NewRowId] = &dataTable[offset];
636 memcpy(indexTable[copy.NewRowId], indexTable[copy.SourceRowId], recordsize);
637 *reinterpret_cast<uint32*>(&dataTable[offset + idFieldOffset]) = copy.NewRowId;
638 offset += recordsize;
639 }
640 }
641}
642
644{
645 int32 parentIdOffset = _loadInfo->Meta->GetParentIndexFieldOffset();
646 uint32 recordSize = _loadInfo->Meta->GetRecordSize();
647 uint32 recordIndexOffset = 0;
648 for (uint32 i = 0; i < _header->SectionCount; ++i)
649 {
650 DB2SectionHeader const& section = GetSection(i);
651 if (IsKnownTactId(section.TactId))
652 {
653 for (std::size_t j = 0; j < _parentIndexes[i][0].Entries.size(); ++j)
654 {
655 uint32 parentId = _parentIndexes[i][0].Entries[j].ParentId;
656 uint32 recordIndex = _parentIndexes[i][0].Entries[j].RecordIndex + recordIndexOffset;
657 char* recordData = &dataTable[recordIndex * recordSize];
658
660 {
661 case FT_SHORT:
662 {
664 {
665 // extra field at the end
666 *reinterpret_cast<uint32*>(&recordData[parentIdOffset]) = parentId;
667 }
668 else
669 {
670 // in data block, must fit
671 ASSERT(parentId <= std::numeric_limits<uint16>::max(), "ParentId value %u does not fit into uint16 field (%s in %s)",
673 *reinterpret_cast<uint16*>(&recordData[parentIdOffset]) = parentId;
674 }
675 break;
676 }
677 case FT_BYTE:
678 {
680 {
681 // extra field at the end
682 *reinterpret_cast<uint32*>(&recordData[parentIdOffset]) = parentId;
683 }
684 else
685 {
686 // in data block, must fit
687 ASSERT(parentId <= std::numeric_limits<uint8>::max(), "ParentId value %u does not fit into uint8 field (%s in %s)",
689 *reinterpret_cast<uint8*>(&recordData[parentIdOffset]) = parentId;
690 }
691 break;
692 }
693 case FT_INT:
694 *reinterpret_cast<uint32*>(&recordData[parentIdOffset]) = parentId;
695 break;
696 default:
697 ABORT_MSG("Unhandled parent id type '%c' found in %s", _loadInfo->Meta->Fields[_loadInfo->Meta->ParentIndexField].Type, _fileName);
698 break;
699 }
700 }
701 }
702 recordIndexOffset += section.RecordCount;
703 }
704}
705
707{
708 return DB2Record(*this, recordNumber, nullptr);
709}
710
712{
713 if (copyNumber >= GetRecordCopyCount())
714 return DB2RecordCopy{};
715
716 return _copyTable[copyNumber];
717}
718
720{
721 return _header->RecordCount;
722}
723
725{
726 return _copyTable.size();
727}
728
730{
731 uint32 section = 0;
732 for (; section < _header->SectionCount; ++section)
733 {
734 DB2SectionHeader const& sectionHeader = GetSection(section);
735 if (recordNumber < sectionHeader.RecordCount)
736 break;
737
738 recordNumber -= sectionHeader.RecordCount;
739 }
740
741 return section;
742}
743
744unsigned char const* DB2FileLoaderRegularImpl::GetRawRecordData(uint32 recordNumber, uint32 const* section) const
745{
746 if (recordNumber >= _header->RecordCount)
747 return nullptr;
748
749 if (!IsKnownTactId(GetSection(section ? *section : GetRecordSection(recordNumber)).TactId))
750 return nullptr;
751
752 return &_data[recordNumber * _header->RecordSize];
753}
754
756{
758 return RecordGetVarInt<uint32>(record, _loadInfo->Meta->GetIndexField(), 0);
759
760 return _idTable[recordIndex];
761}
762
763uint8 DB2FileLoaderRegularImpl::RecordGetUInt8(uint8 const* record, uint32 field, uint32 arrayIndex) const
764{
765 return RecordGetVarInt<uint8>(record, field, arrayIndex);
766}
767
769{
770 return RecordGetVarInt<uint16>(record, field, arrayIndex);
771}
772
774{
775 return RecordGetVarInt<uint32>(record, field, arrayIndex);
776}
777
778int32 DB2FileLoaderRegularImpl::RecordGetInt32(uint8 const* record, uint32 field, uint32 arrayIndex) const
779{
780 return RecordGetVarInt<int32>(record, field, arrayIndex);
781}
782
784{
785 return RecordGetVarInt<uint64>(record, field, arrayIndex);
786}
787
788float DB2FileLoaderRegularImpl::RecordGetFloat(uint8 const* record, uint32 field, uint32 arrayIndex) const
789{
790 return RecordGetVarInt<float>(record, field, arrayIndex);
791}
792
793char const* DB2FileLoaderRegularImpl::RecordGetString(uint8 const* record, uint32 field, uint32 arrayIndex) const
794{
795 uint32 fieldOffset = GetFieldOffset(field) + sizeof(uint32) * arrayIndex;
796 uint32 stringOffset = RecordGetVarInt<uint32>(record, field, arrayIndex);
797 ASSERT(stringOffset < _header->RecordSize * _header->RecordCount + _header->StringTableSize);
798 return stringOffset ? reinterpret_cast<char const*>(record + fieldOffset + stringOffset) : nullptr;
799}
800
801template<typename T>
802T DB2FileLoaderRegularImpl::RecordGetVarInt(uint8 const* record, uint32 field, uint32 arrayIndex) const
803{
804 ASSERT(field < _header->FieldCount);
805 DB2ColumnCompression compressionType = _columnMeta ? _columnMeta[field].CompressionType : DB2ColumnCompression::None;
806 switch (compressionType)
807 {
809 {
810 T val = *reinterpret_cast<T const*>(record + GetFieldOffset(field) + sizeof(T) * arrayIndex);
811 EndianConvert(val);
812 return val;
813 }
815 {
816 ASSERT(arrayIndex == 0);
817 uint64 immediateValue = RecordGetPackedValue(record + GetFieldOffset(field),
818 _columnMeta[field].CompressionData.immediate.BitWidth, _columnMeta[field].CompressionData.immediate.BitOffset);
819 EndianConvert(immediateValue);
820 T value;
821 memcpy(&value, &immediateValue, std::min(sizeof(T), sizeof(immediateValue)));
822 return value;
823 }
825 {
826 uint32 id = RecordGetId(record, (record - _data.get()) / _header->RecordSize);
827 T value;
828 auto valueItr = _commonValues[field].find(id);
829 if (valueItr != _commonValues[field].end())
830 memcpy(&value, &valueItr->second, std::min(sizeof(T), sizeof(uint32)));
831 else
832 memcpy(&value, &_columnMeta[field].CompressionData.commonData.Value, std::min(sizeof(T), sizeof(uint32)));
833 return value;
834 }
836 {
837 ASSERT(arrayIndex == 0);
838 uint64 palletIndex = RecordGetPackedValue(record + GetFieldOffset(field),
839 _columnMeta[field].CompressionData.pallet.BitWidth, _columnMeta[field].CompressionData.pallet.BitOffset);
840 EndianConvert(palletIndex);
841 uint32 palletValue = _palletValues[field][palletIndex].Value;
842 EndianConvert(palletValue);
843 T value;
844 memcpy(&value, &palletValue, std::min(sizeof(T), sizeof(palletValue)));
845 return value;
846 }
848 {
849 uint64 palletIndex = RecordGetPackedValue(record + GetFieldOffset(field),
850 _columnMeta[field].CompressionData.pallet.BitWidth, _columnMeta[field].CompressionData.pallet.BitOffset);
851 EndianConvert(palletIndex);
852 uint32 palletValue = _palletArrayValues[field][palletIndex * _columnMeta[field].CompressionData.pallet.ArraySize + arrayIndex].Value;
853 EndianConvert(palletValue);
854 T value;
855 memcpy(&value, &palletValue, std::min(sizeof(T), sizeof(palletValue)));
856 return value;
857 }
859 {
860 ASSERT(arrayIndex == 0);
861 uint64 immediateValue = RecordGetPackedValue(record + GetFieldOffset(field),
862 _columnMeta[field].CompressionData.immediate.BitWidth, _columnMeta[field].CompressionData.immediate.BitOffset);
863 EndianConvert(immediateValue);
864 uint64 mask = UI64LIT(1) << (_columnMeta[field].CompressionData.immediate.BitWidth - 1);
865 immediateValue = (immediateValue ^ mask) - mask;
866 T value;
867 memcpy(&value, &immediateValue, std::min(sizeof(T), sizeof(immediateValue)));
868 return value;
869 }
870 default:
871 ABORT_MSG("Unhandled compression type %u in %s", uint32(_columnMeta[field].CompressionType), _fileName);
872 break;
873 }
874
875 return 0;
876}
877
878uint64 DB2FileLoaderRegularImpl::RecordGetPackedValue(uint8 const* packedRecordData, uint32 bitWidth, uint32 bitOffset) const
879{
880 uint32 bitsToRead = bitOffset & 7;
881 return *reinterpret_cast<uint64 const*>(packedRecordData) << (64 - bitsToRead - bitWidth) >> (64 - bitWidth);
882}
883
885{
886 ASSERT(field < _header->FieldCount);
887 DB2ColumnCompression compressionType = _columnMeta ? _columnMeta[field].CompressionType : DB2ColumnCompression::None;
888 switch (compressionType)
889 {
891 return _columnMeta[field].BitOffset / 8;
894 return _columnMeta[field].CompressionData.immediate.BitOffset / 8 + _header->PackedDataOffset;
896 return 0xFFFF;
899 return _columnMeta[field].CompressionData.pallet.BitOffset / 8 + _header->PackedDataOffset;
900 default:
901 ABORT_MSG("Unhandled compression type %u in %s", uint32(_columnMeta[field].CompressionType), _fileName);
902 break;
903 }
904
905 return 0;
906}
907
908std::size_t* DB2FileLoaderRegularImpl::RecordCreateDetachedFieldOffsets(std::size_t* /*oldOffsets*/) const
909{
910 return nullptr;
911}
912
913std::size_t* DB2FileLoaderRegularImpl::RecordCopyDetachedFieldOffsets(std::size_t* /*oldOffsets*/) const
914{
915 return nullptr;
916}
917
918void DB2FileLoaderRegularImpl::RecordDestroyFieldOffsets(std::size_t*& /*fieldOffsets*/) const
919{
920}
921
923{
924 uint32 minId = std::numeric_limits<uint32>::max();
925 for (uint32 row = 0; row < _header->RecordCount; ++row)
926 {
927 unsigned char const* rawRecord = GetRawRecordData(row, nullptr);
928 if (!rawRecord)
929 continue;
930
931 uint32 id = RecordGetId(rawRecord, row);
932 if (id < minId)
933 minId = id;
934 }
935
936 for (uint32 copy = 0; copy < GetRecordCopyCount(); ++copy)
937 {
938 uint32 id = GetRecordCopy(copy).NewRowId;
939 if (id < minId)
940 minId = id;
941 }
942
943 if (minId == std::numeric_limits<uint32>::max())
944 minId = 0;
945
946 ASSERT(minId >= _header->MinId);
947 return minId;
948}
949
951{
952 uint32 maxId = 0;
953 for (uint32 row = 0; row < _header->RecordCount; ++row)
954 {
955 unsigned char const* rawRecord = GetRawRecordData(row, nullptr);
956 if (!rawRecord)
957 continue;
958
959 uint32 id = RecordGetId(rawRecord, row);
960 if (id > maxId)
961 maxId = id;
962 }
963
964 for (uint32 copy = 0; copy < GetRecordCopyCount(); ++copy)
965 {
966 uint32 id = GetRecordCopy(copy).NewRowId;
967 if (id > maxId)
968 maxId = id;
969 }
970
971 ASSERT(maxId <= _header->MaxId);
972 return maxId;
973}
974
976{
977 return _loadInfo;
978}
979
981{
982 return _sections[section];
983}
984
986{
987 if (field >= _header->TotalFieldCount)
988 {
989 ASSERT(field == _header->TotalFieldCount);
991 return _loadInfo->Meta->IsSignedField(field);
992 }
993
994 DB2ColumnCompression compressionType = _columnMeta ? _columnMeta[field].CompressionType : DB2ColumnCompression::None;
995 switch (compressionType)
996 {
1001 return _loadInfo->Meta->IsSignedField(field);
1003 return field != uint32(_loadInfo->Meta->IndexField);
1005 return false;
1006 default:
1007 ABORT_MSG("Unhandled compression type %u in %s", uint32(_columnMeta[field].CompressionType), _fileName);
1008 break;
1009 }
1010
1011 return false;
1012}
1013
1015{
1016 if (field >= _header->TotalFieldCount)
1017 {
1018 ASSERT(field == _header->TotalFieldCount);
1020 return " (ParentIndexField must always be unsigned)";
1021 }
1022
1023 DB2ColumnCompression compressionType = _columnMeta ? _columnMeta[field].CompressionType : DB2ColumnCompression::None;
1024 switch (compressionType)
1025 {
1030 if (int32(field) == _loadInfo->Meta->IndexField)
1031 return " (IndexField must always be unsigned)";
1032 if (int32(field) == _loadInfo->Meta->ParentIndexField)
1033 return " (ParentIndexField must always be unsigned)";
1034 return "";
1036 return " (CompressionType is SignedImmediate)";
1038 return " (CompressionType is Immediate)";
1039 default:
1040 ABORT_MSG("Unhandled compression type %u in %s", uint32(_columnMeta[field].CompressionType), _fileName);
1041 break;
1042 }
1043
1044 return "";
1045}
1046
1047DB2FileLoaderSparseImpl::DB2FileLoaderSparseImpl(char const* fileName, DB2FileLoadInfo const* loadInfo, DB2Header const* header, DB2FileSource* source) :
1048 _fileName(fileName),
1049 _loadInfo(loadInfo),
1050 _header(header),
1051 _source(source),
1052 _totalRecordSize(0),
1053 _maxRecordSize(0),
1054 _fieldAndArrayOffsets(loadInfo ? (std::make_unique<std::size_t[]>(loadInfo->Meta->FieldCount + loadInfo->FieldCount - (!loadInfo->Meta->HasIndexFieldInData() ? 1 : 0))) : nullptr)
1055{
1056}
1057
1059
1060void DB2FileLoaderSparseImpl::LoadColumnData(std::unique_ptr<DB2SectionHeader[]> sections, std::unique_ptr<DB2FieldEntry[]> fields, std::unique_ptr<DB2ColumnMeta[]> /*columnMeta*/,
1061 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> /*palletValues*/, std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> /*palletArrayValues*/,
1062 std::unique_ptr<std::unordered_map<uint32, uint32>[]> /*commonValues*/)
1063{
1064 _sections = std::move(sections);
1065 _fields = std::move(fields);
1066}
1067
1069{
1070 _catalogIds.resize(_catalogIds.size() + _sections[section].CatalogDataCount);
1071 _catalog.resize(_catalog.size() + _sections[section].CatalogDataCount);
1072}
1073
1075{
1076 source->SetPosition(_sections[section].CatalogDataOffset);
1077
1078 std::size_t oldSize = _catalog.size();
1079 _catalogIds.resize(oldSize + _sections[section].CatalogDataCount);
1080 if (!source->Read(&_catalogIds[oldSize], sizeof(uint32) * _sections[section].CatalogDataCount))
1081 return false;
1082
1083 if (_sections[section].CopyTableCount)
1084 {
1085 std::size_t oldCopyTableSize = _copyTable.size();
1086 _copyTable.resize(oldCopyTableSize + _sections[section].CopyTableCount);
1087 if (!source->Read(&_copyTable[oldCopyTableSize], sizeof(DB2RecordCopy) * _sections[section].CopyTableCount))
1088 return false;
1089 }
1090
1091 _catalog.resize(oldSize + _sections[section].CatalogDataCount);
1092 if (!source->Read(&_catalog[oldSize], sizeof(DB2CatalogEntry) * _sections[section].CatalogDataCount))
1093 return false;
1094
1095 for (uint32 i = 0; i < _sections[section].CatalogDataCount; ++i)
1096 {
1097 _totalRecordSize += _catalog[oldSize + i].RecordSize;
1098 _maxRecordSize = std::max(_maxRecordSize, _catalog[oldSize + i].RecordSize);
1099 }
1100
1101 return true;
1102}
1103
1104void DB2FileLoaderSparseImpl::SetAdditionalData(std::vector<uint32> /*idTable*/, std::vector<DB2RecordCopy> /*copyTable*/, std::vector<std::vector<DB2IndexData>> parentIndexes)
1105{
1106 _parentIndexes = std::move(parentIndexes);
1107 _recordBuffer = std::make_unique<uint8[]>(_maxRecordSize);
1108}
1109
1110char* DB2FileLoaderSparseImpl::AutoProduceData(uint32& indexTableSize, char**& indexTable)
1111{
1113 throw DB2FileLoadException(Trinity::StringFormat("Found unsupported parent index in sparse db2 {}", _fileName));
1114
1115 //get struct size and index pos
1116 uint32 recordsize = _loadInfo->Meta->GetRecordSize();
1117 uint32 records = _catalog.size();
1118
1119 using index_entry_t = char*;
1120
1121 indexTableSize = _header->MaxId + 1;
1122 indexTable = new index_entry_t[indexTableSize];
1123 memset(indexTable, 0, indexTableSize * sizeof(index_entry_t));
1124
1125 char* dataTable = new char[(records + _copyTable.size()) * recordsize];
1126 memset(dataTable, 0, (records + _copyTable.size()) * recordsize);
1127
1128 uint32 offset = 0;
1129 uint32 y = 0;
1130
1131 for (uint32 section = 0; section < _header->SectionCount; ++section)
1132 {
1133 DB2SectionHeader const& sectionHeader = GetSection(section);
1134 if (!IsKnownTactId(sectionHeader.TactId))
1135 {
1136 offset += recordsize * sectionHeader.RecordCount;
1137 y += sectionHeader.RecordCount;
1138 continue;
1139 }
1140
1141 for (uint32 sr = 0; sr < sectionHeader.CatalogDataCount; ++sr, ++y)
1142 {
1143 unsigned char const* rawRecord = GetRawRecordData(y, &section);
1144 if (!rawRecord)
1145 continue;
1146
1147 uint32 indexVal = _catalogIds[y];
1148 indexTable[indexVal] = &dataTable[offset];
1149
1150 uint32 fieldIndex = 0;
1152 {
1153 *reinterpret_cast<uint32*>(&dataTable[offset]) = indexVal;
1154 offset += 4;
1155 ++fieldIndex;
1156 }
1157
1158 for (uint32 x = 0; x < _header->FieldCount; ++x)
1159 {
1160 for (uint32 z = 0; z < _loadInfo->Meta->Fields[x].ArraySize; ++z)
1161 {
1162 switch (_loadInfo->Fields[fieldIndex].Type)
1163 {
1164 case FT_FLOAT:
1165 *reinterpret_cast<float*>(&dataTable[offset]) = RecordGetFloat(rawRecord, x, z);
1166 offset += 4;
1167 break;
1168 case FT_INT:
1169 *reinterpret_cast<uint32*>(&dataTable[offset]) = RecordGetVarInt(rawRecord, x, z, _loadInfo->Fields[fieldIndex].IsSigned);
1170 offset += 4;
1171 break;
1172 case FT_BYTE:
1173 *reinterpret_cast<uint8*>(&dataTable[offset]) = RecordGetUInt8(rawRecord, x, z);
1174 offset += 1;
1175 break;
1176 case FT_SHORT:
1177 *reinterpret_cast<uint16*>(&dataTable[offset]) = RecordGetUInt16(rawRecord, x, z);
1178 offset += 2;
1179 break;
1180 case FT_LONG:
1181 *reinterpret_cast<uint64*>(&dataTable[offset]) = RecordGetUInt64(rawRecord, x, z);
1182 offset += 8;
1183 break;
1184 case FT_STRING:
1185 for (char const*& localeStr : reinterpret_cast<LocalizedString*>(&dataTable[offset])->Str)
1186 localeStr = EmptyDb2String;
1187
1188 offset += sizeof(LocalizedString);
1189 break;
1191 *reinterpret_cast<char const**>(&dataTable[offset]) = EmptyDb2String;
1192 offset += sizeof(char*);
1193 break;
1194 default:
1195 ABORT_MSG("Unknown format character '%c' found in %s meta for field %s",
1196 _loadInfo->Fields[fieldIndex].Type, _fileName, _loadInfo->Fields[fieldIndex].Name);
1197 break;
1198 }
1199 ++fieldIndex;
1200 }
1201 }
1202
1203 for (uint32 x = _header->FieldCount; x < _loadInfo->Meta->FieldCount; ++x)
1204 {
1205 for (uint32 z = 0; z < _loadInfo->Meta->Fields[x].ArraySize; ++z)
1206 {
1207 switch (_loadInfo->Fields[fieldIndex].Type)
1208 {
1209 case FT_INT:
1210 *reinterpret_cast<uint32*>(&dataTable[offset]) = 0;
1211 offset += 4;
1212 break;
1213 case FT_BYTE:
1214 *reinterpret_cast<uint8*>(&dataTable[offset]) = 0;
1215 offset += 1;
1216 break;
1217 case FT_SHORT:
1218 *reinterpret_cast<uint16*>(&dataTable[offset]) = 0;
1219 offset += 2;
1220 break;
1221 default:
1222 ABORT_MSG("Unknown format character '%c' found in %s meta for parent field %s",
1223 _loadInfo->Fields[fieldIndex].Type, _fileName, _loadInfo->Fields[fieldIndex].Name);
1224 break;
1225 }
1226 ++fieldIndex;
1227 }
1228 }
1229 }
1230 }
1231
1232 return dataTable;
1233}
1234
1235char* DB2FileLoaderSparseImpl::AutoProduceStrings(char** indexTable, uint32 indexTableSize, uint32 locale)
1236{
1238 throw DB2FileLoadException(Trinity::StringFormat("Found unsupported parent index in sparse db2 {}", _fileName));
1239
1240 if (!(_header->Locale & (1 << locale)))
1241 {
1242 char const* sep = "";
1243 std::ostringstream str;
1244 for (uint32 i = 0; i < TOTAL_LOCALES; ++i)
1245 {
1246 if (_header->Locale & (1 << i))
1247 {
1248 str << sep << localeNames[i];
1249 sep = ", ";
1250 }
1251 }
1252
1253 TC_LOG_ERROR("", "Attempted to load {} which has locales {} as {}. Check if you placed your localized db2 files in correct directory.", _fileName, str.str(), localeNames[locale]);
1254 return nullptr;
1255 }
1256
1257 uint32 records = _catalog.size();
1258 uint32 recordsize = _loadInfo->Meta->GetRecordSize();
1259 std::size_t stringFields = _loadInfo->GetStringFieldCount(false);
1260 std::size_t localizedStringFields = _loadInfo->GetStringFieldCount(true);
1261
1262 if (!stringFields)
1263 return nullptr;
1264
1265 std::size_t stringsInRecordSize = (stringFields - localizedStringFields) * sizeof(char*);
1266 std::size_t localizedStringsInRecordSize = localizedStringFields * sizeof(LocalizedString);
1267
1268 // string table size is "total size of all records" - RecordCount * "size of record without strings"
1269 std::size_t stringTableSize = _totalRecordSize - (records * ((recordsize - (!_loadInfo->Meta->HasIndexFieldInData() ? 4 : 0)) - stringsInRecordSize - localizedStringsInRecordSize));
1270
1271 char* stringTable = new char[stringTableSize];
1272 memset(stringTable, 0, stringTableSize);
1273 char* stringPtr = stringTable;
1274
1275 uint32 y = 0;
1276
1277 for (uint32 section = 0; section < _header->SectionCount; ++section)
1278 {
1279 DB2SectionHeader const& sectionHeader = GetSection(section);
1280 if (!IsKnownTactId(sectionHeader.TactId))
1281 {
1282 y += sectionHeader.RecordCount;
1283 continue;
1284 }
1285
1286 for (uint32 sr = 0; sr < sectionHeader.CatalogDataCount; ++sr, ++y)
1287 {
1288 unsigned char const* rawRecord = GetRawRecordData(y, &section);
1289 if (!rawRecord)
1290 continue;
1291
1292 uint32 indexVal = _catalogIds[y];
1293 if (indexVal >= indexTableSize)
1294 continue;
1295
1296 char* recordData = indexTable[indexVal];
1297
1298 uint32 offset = 0;
1299 uint32 fieldIndex = 0;
1301 {
1302 offset += 4;
1303 ++fieldIndex;
1304 }
1305
1306 for (uint32 x = 0; x < _header->FieldCount; ++x)
1307 {
1308 for (uint32 z = 0; z < _loadInfo->Meta->Fields[x].ArraySize; ++z)
1309 {
1310 switch (_loadInfo->Fields[fieldIndex].Type)
1311 {
1312 case FT_FLOAT:
1313 offset += 4;
1314 break;
1315 case FT_INT:
1316 offset += 4;
1317 break;
1318 case FT_BYTE:
1319 offset += 1;
1320 break;
1321 case FT_SHORT:
1322 offset += 2;
1323 break;
1324 case FT_LONG:
1325 offset += 8;
1326 break;
1327 case FT_STRING:
1328 {
1329 LocalizedString* db2str = reinterpret_cast<LocalizedString*>(&recordData[offset]);
1330 db2str->Str[locale] = stringPtr;
1331 strcpy(stringPtr, RecordGetString(rawRecord, x, z));
1332 stringPtr += strlen(stringPtr) + 1;
1333 offset += sizeof(LocalizedString);
1334 break;
1335 }
1337 {
1338 char const** db2str = reinterpret_cast<char const**>(&recordData[offset]);
1339 *db2str = stringPtr;
1340 strcpy(stringPtr, RecordGetString(rawRecord, x, z));
1341 stringPtr += strlen(stringPtr) + 1;
1342 offset += sizeof(char*);
1343 break;
1344 }
1345 default:
1346 ABORT_MSG("Unknown format character '%c' found in %s meta for field %s",
1347 _loadInfo->Fields[fieldIndex].Type, _fileName, _loadInfo->Fields[fieldIndex].Name);
1348 break;
1349 }
1350 ++fieldIndex;
1351 }
1352 }
1353 }
1354 }
1355
1356 return stringTable;
1357}
1358
1359void DB2FileLoaderSparseImpl::AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable)
1360{
1361 uint32 recordCopies = GetRecordCopyCount();
1362 if (!recordCopies)
1363 return;
1364
1365 uint32 recordsize = _loadInfo->Meta->GetRecordSize();
1366 uint32 offset = _header->RecordCount * recordsize;
1368 for (uint32 c = 0; c < recordCopies; ++c)
1369 {
1370 DB2RecordCopy copy = GetRecordCopy(c);
1371 if (copy.SourceRowId && copy.SourceRowId < records && copy.NewRowId < records && indexTable[copy.SourceRowId])
1372 {
1373 indexTable[copy.NewRowId] = &dataTable[offset];
1374 memcpy(indexTable[copy.NewRowId], indexTable[copy.SourceRowId], recordsize);
1375 *reinterpret_cast<uint32*>(&dataTable[offset + idFieldOffset]) = copy.NewRowId;
1376 offset += recordsize;
1377 }
1378 }
1379}
1380
1382{
1383 return DB2Record(*this, recordNumber, _fieldAndArrayOffsets.get());
1384}
1385
1387{
1388 if (copyNumber >= GetRecordCopyCount())
1389 return DB2RecordCopy{};
1390
1391 return _copyTable[copyNumber];
1392}
1393
1395{
1396 return _catalog.size();
1397}
1398
1400{
1401 return _copyTable.size();
1402}
1403
1405{
1406 int32 parentIdOffset = _loadInfo->Meta->GetParentIndexFieldOffset();
1407 uint32 recordSize = _loadInfo->Meta->GetRecordSize();
1408 uint32 recordIndexOffset = 0;
1409 for (uint32 i = 0; i < _header->SectionCount; ++i)
1410 {
1411 DB2SectionHeader const& section = GetSection(i);
1412 if (IsKnownTactId(section.TactId))
1413 {
1414 for (std::size_t j = 0; j < _parentIndexes[i][0].Entries.size(); ++j)
1415 {
1416 uint32 parentId = _parentIndexes[i][0].Entries[j].ParentId;
1417 char* recordData = &dataTable[(_parentIndexes[i][0].Entries[j].RecordIndex + recordIndexOffset) * recordSize];
1418
1420 {
1421 case FT_SHORT:
1422 {
1424 {
1425 // extra field at the end
1426 *reinterpret_cast<uint32*>(&recordData[parentIdOffset]) = parentId;
1427 }
1428 else
1429 {
1430 // in data block, must fit
1431 ASSERT(parentId <= 0xFFFF, "ParentId value %u does not fit into uint16 field (%s in %s)",
1433 *reinterpret_cast<uint16*>(&recordData[parentIdOffset]) = parentId;
1434 }
1435 break;
1436 }
1437 case FT_BYTE:
1438 {
1440 {
1441 // extra field at the end
1442 *reinterpret_cast<uint32*>(&recordData[parentIdOffset]) = parentId;
1443 }
1444 else
1445 {
1446 // in data block, must fit
1447 ASSERT(parentId <= 0xFF, "ParentId value %u does not fit into uint8 field (%s in %s)",
1449 *reinterpret_cast<uint8*>(&recordData[parentIdOffset]) = parentId;
1450 }
1451 break;
1452 }
1453 case FT_INT:
1454 *reinterpret_cast<uint32*>(&recordData[parentIdOffset]) = parentId;
1455 break;
1456 default:
1457 ABORT_MSG("Unhandled parent id type '%c' found in %s", _loadInfo->Meta->Fields[_loadInfo->Meta->ParentIndexField].Type, _fileName);
1458 break;
1459 }
1460 }
1461 }
1462 recordIndexOffset += section.RecordCount;
1463 }
1464}
1465
1467{
1468 uint32 section = 0;
1469 for (; section < _header->SectionCount; ++section)
1470 {
1471 DB2SectionHeader const& sectionHeader = GetSection(section);
1472 if (recordNumber < sectionHeader.CatalogDataCount)
1473 break;
1474
1475 recordNumber -= sectionHeader.CatalogDataCount;
1476 }
1477
1478 return section;
1479}
1480
1481unsigned char const* DB2FileLoaderSparseImpl::GetRawRecordData(uint32 recordNumber, uint32 const* section) const
1482{
1483 if (recordNumber >= _catalog.size())
1484 return nullptr;
1485
1486 if (!IsKnownTactId(GetSection(section ? *section : GetRecordSection(recordNumber)).TactId))
1487 return nullptr;
1488
1489 _source->SetPosition(_catalog[recordNumber].FileOffset);
1490 uint8* rawRecord = _recordBuffer.get();
1491 if (!_source->Read(rawRecord, _catalog[recordNumber].RecordSize))
1492 return nullptr;
1493
1495 return rawRecord;
1496}
1497
1499{
1501 return RecordGetVarInt(record, _loadInfo->Meta->GetIndexField(), 0, false);
1502
1503 return _catalogIds[recordIndex];
1504}
1505
1506uint8 DB2FileLoaderSparseImpl::RecordGetUInt8(uint8 const* record, uint32 field, uint32 arrayIndex) const
1507{
1508 ASSERT(field < _header->FieldCount);
1509 return *reinterpret_cast<uint8 const*>(record + GetFieldOffset(field, arrayIndex));
1510}
1511
1513{
1514 ASSERT(field < _header->FieldCount);
1515 uint16 val = *reinterpret_cast<uint16 const*>(record + GetFieldOffset(field, arrayIndex));
1516 EndianConvert(val);
1517 return val;
1518}
1519
1521{
1522 return RecordGetVarInt(record, field, arrayIndex, false);
1523}
1524
1525int32 DB2FileLoaderSparseImpl::RecordGetInt32(uint8 const* record, uint32 field, uint32 arrayIndex) const
1526{
1527 return int32(RecordGetVarInt(record, field, arrayIndex, true));
1528}
1529
1531{
1532 ASSERT(field < _header->FieldCount);
1533 uint64 val = *reinterpret_cast<uint64 const*>(record + GetFieldOffset(field, arrayIndex));
1534 EndianConvert(val);
1535 return val;
1536}
1537
1538float DB2FileLoaderSparseImpl::RecordGetFloat(uint8 const* record, uint32 field, uint32 arrayIndex) const
1539{
1540 ASSERT(field < _header->FieldCount);
1541 float val = *reinterpret_cast<float const*>(record + GetFieldOffset(field, arrayIndex));
1542 EndianConvert(val);
1543 return val;
1544}
1545
1546char const* DB2FileLoaderSparseImpl::RecordGetString(uint8 const* record, uint32 field, uint32 arrayIndex) const
1547{
1548 ASSERT(field < _header->FieldCount);
1549 return reinterpret_cast<char const*>(record + GetFieldOffset(field, arrayIndex));
1550}
1551
1552uint32 DB2FileLoaderSparseImpl::RecordGetVarInt(uint8 const* record, uint32 field, uint32 arrayIndex, bool isSigned) const
1553{
1554 ASSERT(field < _header->FieldCount);
1555 uint32 val = 0;
1556 memcpy(&val, record + GetFieldOffset(field, arrayIndex), GetFieldSize(field));
1557 EndianConvert(val);
1558 if (isSigned)
1559 return int32(val) << _fields[field].UnusedBits >> _fields[field].UnusedBits;
1560
1561 return val << _fields[field].UnusedBits >> _fields[field].UnusedBits;
1562}
1563
1565{
1566 return uint16(_fieldAndArrayOffsets[_fieldAndArrayOffsets[field] + arrayIndex]);
1567}
1568
1570{
1571 ASSERT(field < _header->FieldCount);
1572 return 4 - _fields[field].UnusedBits / 8;
1573}
1574
1575std::size_t* DB2FileLoaderSparseImpl::RecordCreateDetachedFieldOffsets(std::size_t* oldOffsets) const
1576{
1577 if (oldOffsets != _fieldAndArrayOffsets.get())
1578 return oldOffsets;
1579
1581 std::size_t* newOffsets = new std::size_t[size];
1582 memcpy(newOffsets, _fieldAndArrayOffsets.get(), size * sizeof(std::size_t));
1583 return newOffsets;
1584}
1585
1586std::size_t* DB2FileLoaderSparseImpl::RecordCopyDetachedFieldOffsets(std::size_t* oldOffsets) const
1587{
1588 if (oldOffsets == _fieldAndArrayOffsets.get())
1589 return oldOffsets;
1590
1592 std::size_t* newOffsets = new std::size_t[size];
1593 memcpy(newOffsets, _fieldAndArrayOffsets.get(), size * sizeof(std::size_t));
1594 return newOffsets;
1595}
1596
1597void DB2FileLoaderSparseImpl::RecordDestroyFieldOffsets(std::size_t*& fieldOffsets) const
1598{
1599 if (fieldOffsets == _fieldAndArrayOffsets.get())
1600 return;
1601
1602 delete[] fieldOffsets;
1603 fieldOffsets = nullptr;
1604}
1605
1607{
1608 std::size_t offset = 0;
1609 uint32 combinedField = _loadInfo->Meta->FieldCount;
1610 for (uint32 field = 0; field < _loadInfo->Meta->FieldCount; ++field)
1611 {
1612 _fieldAndArrayOffsets[field] = combinedField;
1613 for (uint32 arr = 0; arr < _loadInfo->Meta->Fields[field].ArraySize; ++arr)
1614 {
1615 _fieldAndArrayOffsets[combinedField] = offset;
1616 switch (_loadInfo->Meta->Fields[field].Type)
1617 {
1618 case FT_BYTE:
1619 case FT_SHORT:
1620 case FT_INT:
1621 case FT_LONG:
1622 offset += GetFieldSize(field);
1623 break;
1624 case FT_FLOAT:
1625 offset += sizeof(float);
1626 break;
1627 case FT_STRING:
1629 offset += strlen(reinterpret_cast<char const*>(rawRecord) + offset) + 1;
1630 break;
1631 default:
1632 ABORT_MSG("Unknown format character '%c' found in %s meta", _loadInfo->Meta->Fields[field].Type, _fileName);
1633 break;
1634 }
1635 ++combinedField;
1636 }
1637 }
1638}
1639
1641{
1642 return _header->MinId;
1643}
1644
1646{
1647 return _header->MaxId;
1648}
1649
1651{
1652 return _loadInfo;
1653}
1654
1656{
1657 return _sections[section];
1658}
1659
1661{
1662 ASSERT(field < _header->FieldCount);
1663 return _loadInfo->Meta->IsSignedField(field);
1664}
1665
1667{
1668 ASSERT(field < _header->FieldCount);
1669 if (int32(field) == _loadInfo->Meta->IndexField)
1670 return " (IndexField must always be unsigned)";
1671 if (int32(field) == _loadInfo->Meta->ParentIndexField)
1672 return " (ParentIndexField must always be unsigned)";
1673 return "";
1674}
1675
1676DB2Record::DB2Record(DB2FileLoaderImpl const& db2, uint32 recordIndex, std::size_t* fieldOffsets)
1677 : _db2(db2), _recordIndex(recordIndex), _recordData(db2.GetRawRecordData(recordIndex, nullptr)), _fieldOffsets(fieldOffsets)
1678{
1679}
1680
1682 : _db2(other._db2), _recordIndex(other._recordIndex), _recordData(other._recordData), _fieldOffsets(_db2.RecordCopyDetachedFieldOffsets(other._fieldOffsets))
1683{
1684}
1685
1687 : _db2(other._db2), _recordIndex(other._recordIndex), _recordData(other._recordData), _fieldOffsets(std::exchange(other._fieldOffsets, nullptr))
1688{
1689}
1690
1692{
1694}
1695
1696DB2Record::operator bool() const
1697{
1698 return _recordData != nullptr;
1699}
1700
1702{
1704}
1705
1706uint8 DB2Record::GetUInt8(uint32 field, uint32 arrayIndex) const
1707{
1708 return _db2.RecordGetUInt8(_recordData, field, arrayIndex);
1709}
1710
1711uint8 DB2Record::GetUInt8(char const* fieldName) const
1712{
1713 std::pair<int32, int32> fieldIndex = _db2.GetLoadInfo()->GetFieldIndexByName(fieldName);
1714 ASSERT(fieldIndex.first != -1, "Field with name %s does not exist!", fieldName);
1715 return _db2.RecordGetUInt8(_recordData, uint32(fieldIndex.first), uint32(fieldIndex.second));
1716}
1717
1719{
1720 return _db2.RecordGetUInt16(_recordData, field, arrayIndex);
1721}
1722
1723uint16 DB2Record::GetUInt16(char const* fieldName) const
1724{
1725 std::pair<int32, int32> fieldIndex = _db2.GetLoadInfo()->GetFieldIndexByName(fieldName);
1726 ASSERT(fieldIndex.first != -1, "Field with name %s does not exist!", fieldName);
1727 return _db2.RecordGetUInt16(_recordData, uint32(fieldIndex.first), uint32(fieldIndex.second));
1728}
1729
1731{
1732 return _db2.RecordGetUInt32(_recordData, field, arrayIndex);
1733}
1734
1735uint32 DB2Record::GetUInt32(char const* fieldName) const
1736{
1737 std::pair<int32, int32> fieldIndex = _db2.GetLoadInfo()->GetFieldIndexByName(fieldName);
1738 ASSERT(fieldIndex.first != -1, "Field with name %s does not exist!", fieldName);
1739 return _db2.RecordGetUInt32(_recordData, uint32(fieldIndex.first), uint32(fieldIndex.second));
1740}
1741
1742int32 DB2Record::GetInt32(uint32 field, uint32 arrayIndex) const
1743{
1744 return _db2.RecordGetInt32(_recordData, field, arrayIndex);
1745}
1746
1747int32 DB2Record::GetInt32(char const* fieldName) const
1748{
1749 std::pair<int32, int32> fieldIndex = _db2.GetLoadInfo()->GetFieldIndexByName(fieldName);
1750 ASSERT(fieldIndex.first != -1, "Field with name %s does not exist!", fieldName);
1751 return _db2.RecordGetInt32(_recordData, uint32(fieldIndex.first), uint32(fieldIndex.second));
1752}
1753
1755{
1756 return _db2.RecordGetUInt64(_recordData, field, arrayIndex);
1757}
1758
1759uint64 DB2Record::GetUInt64(char const* fieldName) const
1760{
1761 std::pair<int32, int32> fieldIndex = _db2.GetLoadInfo()->GetFieldIndexByName(fieldName);
1762 ASSERT(fieldIndex.first != -1, "Field with name %s does not exist!", fieldName);
1763 return _db2.RecordGetUInt64(_recordData, uint32(fieldIndex.first), uint32(fieldIndex.second));
1764}
1765
1766float DB2Record::GetFloat(uint32 field, uint32 arrayIndex) const
1767{
1768 return _db2.RecordGetFloat(_recordData, field, arrayIndex);
1769}
1770
1771float DB2Record::GetFloat(char const* fieldName) const
1772{
1773 std::pair<int32, int32> fieldIndex = _db2.GetLoadInfo()->GetFieldIndexByName(fieldName);
1774 ASSERT(fieldIndex.first != -1, "Field with name %s does not exist!", fieldName);
1775 return _db2.RecordGetFloat(_recordData, uint32(fieldIndex.first), uint32(fieldIndex.second));
1776}
1777
1778char const* DB2Record::GetString(uint32 field, uint32 arrayIndex) const
1779{
1780 return _db2.RecordGetString(_recordData, field, arrayIndex);
1781}
1782
1783char const* DB2Record::GetString(char const* fieldName) const
1784{
1785 std::pair<int32, int32> fieldIndex = _db2.GetLoadInfo()->GetFieldIndexByName(fieldName);
1786 ASSERT(fieldIndex.first != -1, "Field with name %s does not exist!", fieldName);
1787 return _db2.RecordGetString(_recordData, uint32(fieldIndex.first), uint32(fieldIndex.second));
1788}
1789
1791{
1793}
1794
1795DB2FileLoader::DB2FileLoader() : _impl(nullptr), _header()
1796{
1797}
1798
1800{
1801 delete _impl;
1802}
1803
1805{
1806 if (!source->IsOpen())
1807 throw std::system_error(std::make_error_code(std::errc::no_such_file_or_directory));
1808
1809 if (!source->Read(&_header, sizeof(DB2Header)))
1810 throw DB2FileLoadException("Failed to read header");
1811
1832
1833 if (_header.Signature != 0x35434457) //'WDC5'
1834 throw DB2FileLoadException(Trinity::StringFormat("Incorrect file signature in {}, expected 'WDC5', got {}{}{}{}", source->GetFileName(),
1835 char(_header.Signature & 0xFF), char((_header.Signature >> 8) & 0xFF), char((_header.Signature >> 16) & 0xFF), char((_header.Signature >> 24) & 0xFF)));
1836
1837 if (_header.Version != 5)
1838 throw DB2FileLoadException(Trinity::StringFormat("Incorrect version in {}, expected 5, got {} (possibly wrong client version)",
1839 source->GetFileName(), _header.Version));
1840
1841 if (loadInfo && _header.LayoutHash != loadInfo->Meta->LayoutHash)
1842 throw DB2FileLoadException(Trinity::StringFormat("Incorrect layout hash in {}, expected 0x{:08X}, got 0x{:08X} (possibly wrong client version)",
1843 source->GetFileName(), loadInfo->Meta->LayoutHash, _header.LayoutHash));
1844
1845 if (_header.ParentLookupCount > 1)
1846 throw DB2FileLoadException(Trinity::StringFormat("Too many parent lookups in {}, only one is allowed, got {}",
1848
1849 if (loadInfo && (_header.TotalFieldCount + (loadInfo->Meta->ParentIndexField >= int32(_header.TotalFieldCount) ? 1 : 0) != loadInfo->Meta->FieldCount))
1850 throw DB2FileLoadException(Trinity::StringFormat("Incorrect number of fields in {}, expected {}, got {}",
1851 source->GetFileName(), loadInfo->Meta->FieldCount, _header.TotalFieldCount + (loadInfo->Meta->ParentIndexField >= int32(_header.TotalFieldCount) ? 1 : 0)));
1852
1853 if (loadInfo && (_header.ParentLookupCount && loadInfo->Meta->ParentIndexField == -1))
1854 throw DB2FileLoadException(Trinity::StringFormat("Unexpected parent lookup found in {}", source->GetFileName()));
1855
1856 std::unique_ptr<DB2SectionHeader[]> sections = std::make_unique<DB2SectionHeader[]>(_header.SectionCount);
1857 if (_header.SectionCount && !source->Read(sections.get(), sizeof(DB2SectionHeader) * _header.SectionCount))
1858 throw DB2FileLoadException(Trinity::StringFormat("Unable to read section headers from {}", source->GetFileName()));
1859
1860 std::unique_ptr<DB2FieldEntry[]> fieldData = std::make_unique<DB2FieldEntry[]>(_header.FieldCount);
1861 if (!source->Read(fieldData.get(), sizeof(DB2FieldEntry) * _header.FieldCount))
1862 throw DB2FileLoadException(Trinity::StringFormat("Unable to read field information from {}", source->GetFileName()));
1863
1864 std::unique_ptr<DB2ColumnMeta[]> columnMeta;
1865 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletValues;
1866 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletArrayValues;
1867 std::unique_ptr<std::unordered_map<uint32, uint32>[]> commonValues;
1869 {
1870 columnMeta = std::make_unique<DB2ColumnMeta[]>(_header.TotalFieldCount);
1871 if (!source->Read(columnMeta.get(), _header.ColumnMetaSize))
1872 throw DB2FileLoadException(Trinity::StringFormat("Unable to read field metadata from {}", source->GetFileName()));
1873
1874 if (loadInfo && loadInfo->Meta->HasIndexFieldInData())
1875 {
1876 if (columnMeta[loadInfo->Meta->IndexField].CompressionType != DB2ColumnCompression::None
1877 && columnMeta[loadInfo->Meta->IndexField].CompressionType != DB2ColumnCompression::Immediate
1878 && columnMeta[loadInfo->Meta->IndexField].CompressionType != DB2ColumnCompression::SignedImmediate)
1879 throw DB2FileLoadException(Trinity::StringFormat("Invalid compression type for index field in {}, expected one of None (0), Immediate (1), SignedImmediate (5), got {}",
1880 source->GetFileName(), uint32(columnMeta[loadInfo->Meta->IndexField].CompressionType)));
1881 }
1882
1883 palletValues = std::make_unique<std::unique_ptr<DB2PalletValue[]>[]>(_header.TotalFieldCount);
1884 for (uint32 i = 0; i < _header.TotalFieldCount; ++i)
1885 {
1886 if (columnMeta[i].CompressionType != DB2ColumnCompression::Pallet)
1887 continue;
1888
1889 palletValues[i] = std::make_unique<DB2PalletValue[]>(columnMeta[i].AdditionalDataSize / sizeof(DB2PalletValue));
1890 if (!source->Read(palletValues[i].get(), columnMeta[i].AdditionalDataSize))
1891 throw DB2FileLoadException(Trinity::StringFormat("Unable to read field pallet values from {} for field {}", source->GetFileName(), i));
1892 }
1893
1894 palletArrayValues = std::make_unique<std::unique_ptr<DB2PalletValue[]>[]>(_header.TotalFieldCount);
1895 for (uint32 i = 0; i < _header.TotalFieldCount; ++i)
1896 {
1897 if (columnMeta[i].CompressionType != DB2ColumnCompression::PalletArray)
1898 continue;
1899
1900 palletArrayValues[i] = std::make_unique<DB2PalletValue[]>(columnMeta[i].AdditionalDataSize / sizeof(DB2PalletValue));
1901 if (!source->Read(palletArrayValues[i].get(), columnMeta[i].AdditionalDataSize))
1902 throw DB2FileLoadException(Trinity::StringFormat("Unable to read field pallet array values from {} for field {}", source->GetFileName(), i));
1903 }
1904
1905 std::unique_ptr<std::unique_ptr<DB2CommonValue[]>[]> commonData = std::make_unique<std::unique_ptr<DB2CommonValue[]>[]>(_header.TotalFieldCount);
1906 commonValues = std::make_unique<std::unordered_map<uint32, uint32>[]>(_header.TotalFieldCount);
1907 for (uint32 i = 0; i < _header.TotalFieldCount; ++i)
1908 {
1909 if (columnMeta[i].CompressionType != DB2ColumnCompression::CommonData)
1910 continue;
1911
1912 if (!columnMeta[i].AdditionalDataSize)
1913 continue;
1914
1915 commonData[i] = std::make_unique<DB2CommonValue[]>(columnMeta[i].AdditionalDataSize / sizeof(DB2CommonValue));
1916 if (!source->Read(commonData[i].get(), columnMeta[i].AdditionalDataSize))
1917 throw DB2FileLoadException(Trinity::StringFormat("Unable to read field common values from {} for field {}", source->GetFileName(), i));
1918
1919 uint32 numExtraValuesForField = columnMeta[i].AdditionalDataSize / sizeof(DB2CommonValue);
1920 for (uint32 record = 0; record < numExtraValuesForField; ++record)
1921 {
1922 uint32 recordId = commonData[i][record].RecordId;
1923 uint32 value = commonData[i][record].Value;
1924 EndianConvert(value);
1925 commonValues[i][recordId] = value;
1926 }
1927 }
1928 }
1929
1930 if (!(_header.Flags & 0x1))
1931 _impl = new DB2FileLoaderRegularImpl(source->GetFileName(), loadInfo, &_header);
1932 else
1933 _impl = new DB2FileLoaderSparseImpl(source->GetFileName(), loadInfo, &_header, source);
1934
1935 _impl->LoadColumnData(std::move(sections), std::move(fieldData), std::move(columnMeta), std::move(palletValues), std::move(palletArrayValues), std::move(commonValues));
1936}
1937
1939{
1940 LoadHeaders(source, loadInfo);
1941
1942 std::vector<uint32> idTable;
1943 std::vector<DB2RecordCopy> copyTable;
1944 std::vector<std::vector<DB2IndexData>> parentIndexes;
1945 if (loadInfo && !loadInfo->Meta->HasIndexFieldInData() && _header.RecordCount)
1946 idTable.reserve(_header.RecordCount);
1947
1949 {
1950 parentIndexes.resize(_header.SectionCount);
1951 for (std::vector<DB2IndexData>& parentIndexesForSection : parentIndexes)
1952 parentIndexesForSection.resize(_header.ParentLookupCount);
1953 }
1954
1955 for (uint32 i = 0; i < _header.SectionCount; ++i)
1956 {
1957 DB2SectionHeader& section = _impl->GetSection(i);
1958
1959 if (section.TactId)
1960 {
1961 uint32 encryptedIdCount;
1962 if (!source->Read(&encryptedIdCount, sizeof(encryptedIdCount)))
1963 throw DB2FileLoadException(Trinity::StringFormat("Unable to read number of encrypted records in {} for section {}", source->GetFileName(), i));
1964
1965 // it doesnt matter what the encrypted ids are, we have no use for them
1966 source->SetPosition(source->GetPosition() + sizeof(uint32) * encryptedIdCount);
1967 }
1968 }
1969
1970 if (loadInfo && !(_header.Flags & 0x1))
1971 {
1972 uint32 totalCopyTableSize = 0;
1973 uint32 totalParentLookupDataSize = 0;
1974 for (uint32 i = 0; i < _header.SectionCount; ++i)
1975 {
1976 DB2SectionHeader& section = _impl->GetSection(i);
1977 totalCopyTableSize += section.CopyTableCount * sizeof(DB2RecordCopy);
1978 totalParentLookupDataSize += section.ParentLookupDataSize;
1979 }
1980
1981 int64 expectedFileSize =
1982 source->GetPosition() +
1985 (loadInfo->Meta->IndexField == -1 ? sizeof(uint32) * _header.RecordCount : 0) +
1986 totalCopyTableSize +
1987 totalParentLookupDataSize;
1988
1989 if (source->GetFileSize() != expectedFileSize)
1990 throw DB2FileLoadException(Trinity::StringFormat("{} failed size consistency check, expected {}, got {}", source->GetFileName(), expectedFileSize, source->GetFileSize()));
1991 }
1992
1993 for (uint32 i = 0; i < _header.SectionCount; ++i)
1994 {
1995 DB2SectionHeader& section = _impl->GetSection(i);
1996
1997 if (!IsKnownTactId(section.TactId))
1998 {
1999 switch (source->HandleEncryptedSection(section))
2000 {
2003 idTable.resize(idTable.size() + section.IdTableSize / sizeof(uint32));
2004 continue;
2006 section.TactId = DUMMY_KNOWN_TACT_ID;
2007 break;
2008 default:
2009 break;
2010 }
2011 }
2012
2013 if (!source->SetPosition(section.FileOffset))
2014 throw DB2FileLoadException(Trinity::StringFormat("Unable to change {} read position for section {}", source->GetFileName(), i));
2015
2016 if (!_impl->LoadTableData(source, i))
2017 throw DB2FileLoadException(Trinity::StringFormat("Unable to read section table data from {} for section {}", source->GetFileName(), i));
2018
2019 if (!_impl->LoadCatalogData(source, i))
2020 throw DB2FileLoadException(Trinity::StringFormat("Unable to read section catalog data from {} for section {}", source->GetFileName(), i));
2021
2022 if (loadInfo)
2023 {
2024 if (loadInfo->Meta->HasIndexFieldInData())
2025 {
2026 if (section.IdTableSize != 0)
2027 throw DB2FileLoadException(Trinity::StringFormat("Unexpected id table found in {} for section {}", source->GetFileName(), i));
2028 }
2029 else if (section.IdTableSize != 4 * section.RecordCount)
2030 throw DB2FileLoadException(Trinity::StringFormat("Unexpected id table size in {} for section {}, expected {}, got {}",
2031 source->GetFileName(), i, 4 * section.RecordCount, section.IdTableSize));
2032 }
2033
2034 if (section.IdTableSize)
2035 {
2036 std::size_t idTableSize = idTable.size();
2037 idTable.resize(idTableSize + section.IdTableSize / sizeof(uint32));
2038 if (!source->Read(&idTable[idTableSize], section.IdTableSize))
2039 throw DB2FileLoadException(Trinity::StringFormat("Unable to read non-inline record ids from {} for section {}", source->GetFileName(), i));
2040
2041 // This is a hack fix for broken db2 files that have invalid id tables
2042 for (std::size_t i = idTableSize; i < idTable.size(); ++i)
2043 if (idTable[i] <= _header.MinId)
2044 idTable[i] = _header.MinId + i;
2045 }
2046
2047 if (!(_header.Flags & 0x1) && section.CopyTableCount)
2048 {
2049 std::size_t copyTableSize = copyTable.size();
2050 copyTable.resize(copyTableSize + section.CopyTableCount);
2051 if (!source->Read(&copyTable[copyTableSize], section.CopyTableCount * sizeof(DB2RecordCopy)))
2052 throw DB2FileLoadException(Trinity::StringFormat("Unable to read record copies from {} for section {}", source->GetFileName(), i));
2053 }
2054
2056 {
2057 std::vector<DB2IndexData>& parentIndexesForSection = parentIndexes[i];
2058 for (uint32 j = 0; j < _header.ParentLookupCount; ++j)
2059 {
2060 DB2IndexDataInfo indexInfo;
2061 if (!source->Read(&indexInfo, sizeof(DB2IndexDataInfo)))
2062 throw DB2FileLoadException(Trinity::StringFormat("Unable to read parent lookup info from {} for section {}", source->GetFileName(), i));
2063
2064 if (!indexInfo.NumEntries)
2065 continue;
2066
2067 parentIndexesForSection[j].Entries.resize(indexInfo.NumEntries);
2068 if (!source->Read(parentIndexesForSection[j].Entries.data(), sizeof(DB2IndexEntry) * indexInfo.NumEntries))
2069 throw DB2FileLoadException(Trinity::StringFormat("Unable to read parent lookup content from {} for section {}", source->GetFileName(), i));
2070 }
2071 }
2072 }
2073
2074 _impl->SetAdditionalData(std::move(idTable), std::move(copyTable), std::move(parentIndexes));
2075
2076 if (loadInfo)
2077 {
2078 uint32 fieldIndex = 0;
2079 if (!loadInfo->Meta->HasIndexFieldInData())
2080 {
2081 ASSERT(!loadInfo->Fields[0].IsSigned, "ID must be unsigned in %s", source->GetFileName());
2082 ++fieldIndex;
2083 }
2084 for (uint32 f = 0; f < loadInfo->Meta->FieldCount; ++f)
2085 {
2086 ASSERT(loadInfo->Fields[fieldIndex].IsSigned == _impl->IsSignedField(f),
2087 "Field %s in %s must be %s%s", loadInfo->Fields[fieldIndex].Name, source->GetFileName(), _impl->IsSignedField(f) ? "signed" : "unsigned",
2089
2090 fieldIndex += loadInfo->Meta->Fields[f].ArraySize;
2091 }
2092 }
2093}
2094
2095char* DB2FileLoader::AutoProduceData(uint32& indexTableSize, char**& indexTable)
2096{
2097 return _impl->AutoProduceData(indexTableSize, indexTable);
2098}
2099
2100char* DB2FileLoader::AutoProduceStrings(char** indexTable, uint32 indexTableSize, LocaleConstant locale)
2101{
2102 return _impl->AutoProduceStrings(indexTable, indexTableSize, locale);
2103}
2104
2105void DB2FileLoader::AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable)
2106{
2107 _impl->AutoProduceRecordCopies(records, indexTable, dataTable);
2108}
2109
2111{
2112 return _impl->GetRecordCount();
2113}
2114
2116{
2117 return _impl->GetRecordCopyCount();
2118}
2119
2121{
2122 return _impl->GetMinId();
2123}
2124
2126{
2127 return _impl->GetMaxId();
2128}
2129
2131{
2132 return _impl->GetSection(section);
2133}
2134
2136{
2137 return _impl->GetRecord(recordNumber);
2138}
2139
2141{
2142 return _impl->GetRecordCopy(copyNumber);
2143}
void EndianConvert(T &val)
Definition: ByteConverter.h:48
char const * localeNames[TOTAL_LOCALES]
Definition: Common.cpp:20
LocaleConstant
Definition: Common.h:48
@ TOTAL_LOCALES
Definition: Common.h:62
DB2ColumnCompression
static bool IsKnownTactId(uint64 tactId)
static char const *const EmptyDb2String
constinit uint64 DUMMY_KNOWN_TACT_ID
Definition: DB2FileLoader.h:71
uint8_t uint8
Definition: Define.h:144
int64_t int64
Definition: Define.h:137
int16_t int16
Definition: Define.h:139
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
#define UI64LIT(N)
Definition: Define.h:127
uint16_t uint16
Definition: Define.h:143
@ 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
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
virtual char * AutoProduceData(uint32 &indexTableSize, char **&indexTable)=0
virtual uint64 RecordGetUInt64(uint8 const *record, uint32 field, uint32 arrayIndex) const =0
virtual uint32 GetMaxId() const =0
virtual uint32 GetRecordCopyCount() const =0
virtual DB2SectionHeader & GetSection(uint32 section) const =0
DB2FileLoaderImpl()=default
virtual bool IsSignedField(uint32 field) const =0
virtual ~DB2FileLoaderImpl()=default
virtual DB2FileLoadInfo const * GetLoadInfo() const =0
virtual uint32 RecordGetId(uint8 const *record, uint32 recordIndex) const =0
virtual float RecordGetFloat(uint8 const *record, uint32 field, uint32 arrayIndex) const =0
virtual void SetAdditionalData(std::vector< uint32 > idTable, std::vector< DB2RecordCopy > copyTable, std::vector< std::vector< DB2IndexData > > parentIndexes)=0
virtual void LoadColumnData(std::unique_ptr< DB2SectionHeader[]> sections, std::unique_ptr< DB2FieldEntry[]> fields, std::unique_ptr< DB2ColumnMeta[]> columnMeta, std::unique_ptr< std::unique_ptr< DB2PalletValue[]>[]> palletValues, std::unique_ptr< std::unique_ptr< DB2PalletValue[]>[]> palletArrayValues, std::unique_ptr< std::unordered_map< uint32, uint32 >[]> commonValues)=0
virtual std::size_t * RecordCopyDetachedFieldOffsets(std::size_t *oldOffsets) const =0
virtual std::size_t * RecordCreateDetachedFieldOffsets(std::size_t *oldOffsets) const =0
virtual char const * GetExpectedSignMismatchReason(uint32 field) const =0
virtual uint32 GetMinId() const =0
virtual DB2Record GetRecord(uint32 recordNumber) const =0
virtual DB2RecordCopy GetRecordCopy(uint32 copyNumber) const =0
virtual uint32 RecordGetUInt32(uint8 const *record, uint32 field, uint32 arrayIndex) const =0
virtual char const * RecordGetString(uint8 const *record, uint32 field, uint32 arrayIndex) const =0
DB2FileLoaderImpl(DB2FileLoaderImpl const &other)=delete
virtual bool LoadCatalogData(DB2FileSource *source, uint32 section)=0
virtual bool LoadTableData(DB2FileSource *source, uint32 section)=0
DB2FileLoaderImpl(DB2FileLoaderImpl &&other) noexcept=delete
virtual void AutoProduceRecordCopies(uint32 records, char **indexTable, char *dataTable)=0
virtual void SkipEncryptedSection(uint32 section)=0
friend class DB2Record
virtual int32 RecordGetInt32(uint8 const *record, uint32 field, uint32 arrayIndex) const =0
virtual uint32 GetRecordCount() const =0
virtual uint8 RecordGetUInt8(uint8 const *record, uint32 field, uint32 arrayIndex) const =0
virtual unsigned char const * GetRawRecordData(uint32 recordNumber, uint32 const *section) const =0
virtual void RecordDestroyFieldOffsets(std::size_t *&fieldOffsets) const =0
virtual char * AutoProduceStrings(char **indexTable, uint32 indexTableSize, uint32 locale)=0
virtual uint16 RecordGetUInt16(uint8 const *record, uint32 field, uint32 arrayIndex) const =0
DB2FileLoaderImpl & operator=(DB2FileLoaderImpl const &other)=delete
DB2FileLoaderImpl & operator=(DB2FileLoaderImpl &&other) noexcept=delete
std::unique_ptr< DB2ColumnMeta[]> _columnMeta
void FillParentLookup(char *dataTable)
char * AutoProduceData(uint32 &indexTableSize, char **&indexTable) override
DB2FileLoadInfo const * _loadInfo
uint64 RecordGetPackedValue(uint8 const *packedRecordData, uint32 bitWidth, uint32 bitOffset) const
DB2FileLoaderRegularImpl(char const *fileName, DB2FileLoadInfo const *loadInfo, DB2Header const *header)
DB2FileLoaderRegularImpl & operator=(DB2FileLoaderRegularImpl &&other) noexcept=delete
DB2Header const * _header
uint32 GetRecordSection(uint32 recordNumber) const
DB2SectionHeader & GetSection(uint32 section) const override
std::size_t * RecordCreateDetachedFieldOffsets(std::size_t *oldOffsets) const override
bool LoadCatalogData(DB2FileSource *, uint32) override
std::unique_ptr< std::unique_ptr< DB2PalletValue[]>[]> _palletArrayValues
uint32 GetMaxId() const override
uint8 RecordGetUInt8(uint8 const *record, uint32 field, uint32 arrayIndex) const override
unsigned char const * GetRawRecordData(uint32 recordNumber, uint32 const *section) const override
uint32 GetRecordCopyCount() const override
std::unique_ptr< DB2SectionHeader[]> _sections
uint32 RecordGetUInt32(uint8 const *record, uint32 field, uint32 arrayIndex) const override
float RecordGetFloat(uint8 const *record, uint32 field, uint32 arrayIndex) const override
void SkipEncryptedSection(uint32) override
void SetAdditionalData(std::vector< uint32 > idTable, std::vector< DB2RecordCopy > copyTable, std::vector< std::vector< DB2IndexData > > parentIndexes) override
void LoadColumnData(std::unique_ptr< DB2SectionHeader[]> sections, std::unique_ptr< DB2FieldEntry[]> fields, std::unique_ptr< DB2ColumnMeta[]> columnMeta, std::unique_ptr< std::unique_ptr< DB2PalletValue[]>[]> palletValues, std::unique_ptr< std::unique_ptr< DB2PalletValue[]>[]> palletArrayValues, std::unique_ptr< std::unordered_map< uint32, uint32 >[]> commonValues) override
char const * GetExpectedSignMismatchReason(uint32 field) const override
char const * RecordGetString(uint8 const *record, uint32 field, uint32 arrayIndex) const override
void RecordDestroyFieldOffsets(std::size_t *&fieldOffsets) const override
std::vector< DB2RecordCopy > _copyTable
std::unique_ptr< std::unique_ptr< DB2PalletValue[]>[]> _palletValues
DB2Record GetRecord(uint32 recordNumber) const override
std::unique_ptr< uint8[]> _data
DB2RecordCopy GetRecordCopy(uint32 copyNumber) const override
DB2FileLoaderRegularImpl & operator=(DB2FileLoaderRegularImpl const &other)=delete
DB2FileLoadInfo const * GetLoadInfo() const override
uint32 RecordGetId(uint8 const *record, uint32 recordIndex) const override
char * AutoProduceStrings(char **indexTable, uint32 indexTableSize, uint32 locale) override
bool IsSignedField(uint32 field) const override
uint16 GetFieldOffset(uint32 field) const
uint64 RecordGetUInt64(uint8 const *record, uint32 field, uint32 arrayIndex) const override
DB2FileLoaderRegularImpl(DB2FileLoaderRegularImpl const &other)=delete
std::vector< std::vector< DB2IndexData > > _parentIndexes
uint32 GetRecordCount() const override
void AutoProduceRecordCopies(uint32 records, char **indexTable, char *dataTable) override
std::size_t * RecordCopyDetachedFieldOffsets(std::size_t *oldOffsets) const override
DB2FileLoaderRegularImpl(DB2FileLoaderRegularImpl &&other) noexcept=delete
int32 RecordGetInt32(uint8 const *record, uint32 field, uint32 arrayIndex) const override
std::vector< uint32 > _idTable
std::unique_ptr< std::unordered_map< uint32, uint32 >[]> _commonValues
uint16 RecordGetUInt16(uint8 const *record, uint32 field, uint32 arrayIndex) const override
bool LoadTableData(DB2FileSource *source, uint32 section) override
uint32 GetMinId() const override
T RecordGetVarInt(uint8 const *record, uint32 field, uint32 arrayIndex) const
std::unique_ptr< uint8[]> _recordBuffer
DB2FileSource *const _source
void FillParentLookup(char *dataTable)
void CalculateAndStoreFieldOffsets(uint8 const *rawRecord) const
DB2FileLoaderSparseImpl(DB2FileLoaderSparseImpl const &other)=delete
char const * GetExpectedSignMismatchReason(uint32 field) const override
bool LoadTableData(DB2FileSource *, uint32) override
void RecordDestroyFieldOffsets(std::size_t *&fieldOffsets) const override
DB2FileLoadInfo const * _loadInfo
std::vector< DB2RecordCopy > _copyTable
DB2SectionHeader & GetSection(uint32 section) const override
uint32 GetRecordSection(uint32 recordNumber) const
uint32 GetMinId() const override
std::vector< std::vector< DB2IndexData > > _parentIndexes
uint32 GetMaxId() const override
std::unique_ptr< DB2FieldEntry[]> _fields
unsigned char const * GetRawRecordData(uint32 recordNumber, uint32 const *section) const override
DB2Record GetRecord(uint32 recordNumber) const override
uint32 GetRecordCopyCount() const override
char * AutoProduceData(uint32 &indexTableSize, char **&indexTable) override
char const * RecordGetString(uint8 const *record, uint32 field, uint32 arrayIndex) const override
DB2FileLoaderSparseImpl(char const *fileName, DB2FileLoadInfo const *loadInfo, DB2Header const *header, DB2FileSource *source)
void SkipEncryptedSection(uint32 section) override
uint32 RecordGetVarInt(uint8 const *record, uint32 field, uint32 arrayIndex, bool isSigned) const
DB2RecordCopy GetRecordCopy(uint32 copyNumber) const override
float RecordGetFloat(uint8 const *record, uint32 field, uint32 arrayIndex) const override
uint64 RecordGetUInt64(uint8 const *record, uint32 field, uint32 arrayIndex) const override
bool LoadCatalogData(DB2FileSource *source, uint32 section) override
DB2FileLoaderSparseImpl(DB2FileLoaderSparseImpl &&other) noexcept=delete
uint32 RecordGetId(uint8 const *record, uint32 recordIndex) const override
uint32 RecordGetUInt32(uint8 const *record, uint32 field, uint32 arrayIndex) const override
DB2Header const * _header
DB2FileLoadInfo const * GetLoadInfo() const override
bool IsSignedField(uint32 field) const override
DB2FileLoaderSparseImpl & operator=(DB2FileLoaderSparseImpl const &other)=delete
std::unique_ptr< DB2SectionHeader[]> _sections
std::size_t * RecordCopyDetachedFieldOffsets(std::size_t *oldOffsets) const override
DB2FileLoaderSparseImpl & operator=(DB2FileLoaderSparseImpl &&other) noexcept=delete
std::unique_ptr< std::size_t[]> _fieldAndArrayOffsets
void SetAdditionalData(std::vector< uint32 > idTable, std::vector< DB2RecordCopy > copyTable, std::vector< std::vector< DB2IndexData > > parentIndexes) override
std::vector< DB2CatalogEntry > _catalog
std::vector< uint32 > _catalogIds
uint16 GetFieldOffset(uint32 field, uint32 arrayIndex) const
uint8 RecordGetUInt8(uint8 const *record, uint32 field, uint32 arrayIndex) const override
int32 RecordGetInt32(uint8 const *record, uint32 field, uint32 arrayIndex) const override
std::size_t * RecordCreateDetachedFieldOffsets(std::size_t *oldOffsets) const override
void LoadColumnData(std::unique_ptr< DB2SectionHeader[]> sections, std::unique_ptr< DB2FieldEntry[]> fields, std::unique_ptr< DB2ColumnMeta[]> columnMeta, std::unique_ptr< std::unique_ptr< DB2PalletValue[]>[]> palletValues, std::unique_ptr< std::unique_ptr< DB2PalletValue[]>[]> palletArrayValues, std::unique_ptr< std::unordered_map< uint32, uint32 >[]> commonValues) override
uint16 GetFieldSize(uint32 field) const
uint32 GetRecordCount() const override
uint16 RecordGetUInt16(uint8 const *record, uint32 field, uint32 arrayIndex) const override
char * AutoProduceStrings(char **indexTable, uint32 indexTableSize, uint32 locale) override
void AutoProduceRecordCopies(uint32 records, char **indexTable, char *dataTable) override
DB2Header _header
uint32 GetMaxId() const
uint32 GetMinId() const
void Load(DB2FileSource *source, DB2FileLoadInfo const *loadInfo)
DB2Record GetRecord(uint32 recordNumber) const
DB2RecordCopy GetRecordCopy(uint32 copyNumber) const
char * AutoProduceData(uint32 &indexTableSize, char **&indexTable)
char * AutoProduceStrings(char **indexTable, uint32 indexTableSize, LocaleConstant locale)
void LoadHeaders(DB2FileSource *source, DB2FileLoadInfo const *loadInfo)
DB2SectionHeader const & GetSectionHeader(uint32 section) const
uint32 GetRecordCopyCount() const
DB2FileLoaderImpl * _impl
void AutoProduceRecordCopies(uint32 records, char **indexTable, char *dataTable)
uint32 GetRecordCount() const
uint64 GetUInt64(uint32 field, uint32 arrayIndex) const
float GetFloat(uint32 field, uint32 arrayIndex) const
DB2Record(DB2FileLoaderImpl const &db2, uint32 recordIndex, std::size_t *fieldOffsets)
DB2FileLoaderImpl const & _db2
int32 GetInt32(uint32 field, uint32 arrayIndex) const
std::size_t * _fieldOffsets
uint32 GetUInt32(uint32 field, uint32 arrayIndex) const
uint16 GetUInt16(uint32 field, uint32 arrayIndex) const
uint8 GetUInt8(uint32 field, uint32 arrayIndex) const
uint32 GetId() const
char const * GetString(uint32 field, uint32 arrayIndex) const
unsigned char const * _recordData
uint32 _recordIndex
void MakePersistent()
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default TC string format function.
Definition: StringFormat.h:38
constexpr std::size_t size()
Definition: UpdateField.h:796
STL namespace.
struct DB2ColumnMeta::@1::@2 immediate
union DB2ColumnMeta::@1 CompressionData
DB2ColumnCompression CompressionType
struct DB2ColumnMeta::@1::@3 commonData
uint32 AdditionalDataSize
struct DB2ColumnMeta::@1::@4 pallet
char const * Name
Definition: DB2FileLoader.h:77
DBCFormer Type
Definition: DB2FileLoader.h:76
std::size_t FieldCount
Definition: DB2FileLoader.h:90
std::pair< int32, int32 > GetFieldIndexByName(char const *fieldName) const
DB2Meta const * Meta
Definition: DB2FileLoader.h:91
uint32 GetStringFieldCount(bool localizedOnly) const
int32 GetFieldIndexByMetaIndex(uint32 metaIndex) const
DB2FieldMeta const * Fields
Definition: DB2FileLoader.h:89
virtual int64 GetFileSize() const =0
virtual DB2EncryptedSectionHandling HandleEncryptedSection(DB2SectionHeader const &sectionHeader) const =0
virtual char const * GetFileName() const =0
virtual bool IsOpen() const =0
virtual bool SetPosition(int64 position)=0
virtual ~DB2FileSource()
virtual bool Read(void *buffer, std::size_t numBytes)=0
virtual int64 GetPosition() const =0
uint32 TotalFieldCount
Definition: DB2FileLoader.h:47
uint32 SectionCount
Definition: DB2FileLoader.h:53
uint32 RecordCount
Definition: DB2FileLoader.h:36
uint32 PackedDataOffset
Definition: DB2FileLoader.h:48
uint32 CommonDataSize
Definition: DB2FileLoader.h:51
uint32 StringTableSize
Definition: DB2FileLoader.h:39
uint32 MaxId
Definition: DB2FileLoader.h:43
uint32 PalletDataSize
Definition: DB2FileLoader.h:52
uint32 ColumnMetaSize
Definition: DB2FileLoader.h:50
uint32 Signature
Definition: DB2FileLoader.h:33
uint16 Flags
Definition: DB2FileLoader.h:45
uint32 TableHash
Definition: DB2FileLoader.h:40
uint32 FieldCount
Definition: DB2FileLoader.h:37
uint32 LayoutHash
Definition: DB2FileLoader.h:41
uint32 RecordSize
Definition: DB2FileLoader.h:38
int16 IndexField
Definition: DB2FileLoader.h:46
uint32 ParentLookupCount
Definition: DB2FileLoader.h:49
uint32 MinId
Definition: DB2FileLoader.h:42
uint32 Version
Definition: DB2FileLoader.h:34
uint32 Locale
Definition: DB2FileLoader.h:44
std::vector< DB2IndexEntry > Entries
uint8 ArraySize
Definition: DB2Meta.h:26
DBCFormer Type
Definition: DB2Meta.h:25
uint32 FileFieldCount
Definition: DB2Meta.h:58
int32 IndexField
Definition: DB2Meta.h:55
DB2MetaField const * Fields
Definition: DB2Meta.h:60
uint32 GetIndexField() const
Definition: DB2Meta.cpp:27
uint32 GetRecordSize() const
Definition: DB2Meta.cpp:32
bool HasIndexFieldInData() const
Definition: DB2Meta.cpp:22
uint32 GetIndexFieldOffset() const
Definition: DB2Meta.cpp:79
uint32 FieldCount
Definition: DB2Meta.h:57
uint32 LayoutHash
Definition: DB2Meta.h:59
bool IsSignedField(uint32 field) const
Definition: DB2Meta.cpp:195
int32 ParentIndexField
Definition: DB2Meta.h:56
int32 GetParentIndexFieldOffset() const
Definition: DB2Meta.cpp:127
uint32 SourceRowId
uint32 CatalogDataCount
Definition: DB2FileLoader.h:65
uint32 ParentLookupDataSize
Definition: DB2FileLoader.h:64
std::array< char const *, TOTAL_LOCALES > Str
Definition: Common.h:109