2017-03-08 18:10:02 +01:00
/*
2020-01-02 06:44:10 +01:00
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
2017-03-08 18:10:02 +01:00
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "DB2FileLoader.h"
#include "ByteConverter.h"
#include "Common.h"
#include "DB2Meta.h"
#include "Errors.h"
#include "Log.h"
2017-05-11 22:29:51 +02:00
#include <sstream>
2017-03-08 18:10:02 +01:00
2018-02-18 16:32:03 +01:00
enum class DB2ColumnCompression : uint32
{
None ,
Immediate ,
CommonData ,
Pallet ,
2018-03-16 18:44:57 +01:00
PalletArray ,
SignedImmediate
2018-02-18 16:32:03 +01:00
};
#pragma pack(push, 1)
struct DB2FieldEntry
{
int16 UnusedBits ;
uint16 Offset ;
};
struct DB2CatalogEntry
{
uint32 FileOffset ;
uint16 RecordSize ;
};
struct DB2ColumnMeta
{
uint16 BitOffset ;
uint16 BitSize ;
uint32 AdditionalDataSize ;
DB2ColumnCompression CompressionType ;
union
{
struct
{
uint32 BitOffset ;
uint32 BitWidth ;
bool Signed ;
} immediate ;
struct
{
uint32 Value ;
} commonData ;
struct
{
uint32 BitOffset ;
uint32 BitWidth ;
uint32 ArraySize ;
} pallet ;
} CompressionData ;
};
struct DB2CommonValue
{
uint32 RecordId ;
uint32 Value ;
};
struct DB2PalletValue
{
uint32 Value ;
};
struct DB2IndexDataInfo
{
uint32 NumEntries ;
uint32 MinId ;
uint32 MaxId ;
};
struct DB2IndexEntry
{
uint32 ParentId ;
uint32 RecordIndex ;
};
#pragma pack(pop)
struct DB2IndexData
{
2019-06-08 13:19:48 +02:00
std :: vector < DB2IndexEntry > Entries ;
2018-02-18 16:32:03 +01:00
};
2018-03-16 18:44:57 +01:00
DB2FieldMeta :: DB2FieldMeta ( bool isSigned , DBCFormer type , char const * name )
: IsSigned ( isSigned ), Type ( type ), Name ( name )
{
}
2017-03-08 18:10:02 +01:00
DB2FileLoadInfo :: DB2FileLoadInfo () : Fields ( nullptr ), FieldCount ( 0 ), Meta ( nullptr )
{
}
DB2FileLoadInfo :: DB2FileLoadInfo ( DB2FieldMeta const * fields , std :: size_t fieldCount , DB2Meta const * meta )
: Fields ( fields ), FieldCount ( fieldCount ), Meta ( meta )
{
TypesString . reserve ( FieldCount );
for ( std :: size_t i = 0 ; i < FieldCount ; ++ i )
TypesString += char ( Fields [ i ]. Type );
}
uint32 DB2FileLoadInfo :: GetStringFieldCount ( bool localizedOnly ) const
{
uint32 stringFields = 0 ;
2017-04-06 23:39:34 +02:00
for ( char fieldType : TypesString )
if ( fieldType == FT_STRING || ( fieldType == FT_STRING_NOT_LOCALIZED && ! localizedOnly ))
2017-03-08 18:10:02 +01:00
++ stringFields ;
return stringFields ;
}
2017-04-17 00:03:44 +02:00
std :: pair < int32 , int32 > DB2FileLoadInfo :: GetFieldIndexByName ( char const * fieldName ) const
{
std :: size_t ourIndex = Meta -> HasIndexFieldInData () ? 0 : 1 ;
for ( uint32 i = 0 ; i < Meta -> FieldCount ; ++ i )
{
2018-03-16 18:44:57 +01:00
for ( uint8 arr = 0 ; arr < Meta -> Fields [ i ]. ArraySize ; ++ arr )
2017-04-17 00:03:44 +02:00
{
if ( ! strcmp ( Fields [ ourIndex ]. Name , fieldName ))
return std :: make_pair ( int32 ( i ), int32 ( arr ));
++ ourIndex ;
}
}
return std :: make_pair ( - 1 , - 1 );
}
2019-11-28 00:23:09 +01:00
int32 DB2FileLoadInfo :: GetFieldIndexByMetaIndex ( uint32 metaIndex ) const
{
ASSERT ( metaIndex < Meta -> FieldCount );
int32 ourIndex = Meta -> HasIndexFieldInData () ? 0 : 1 ;
for ( uint32 i = 0 ; i < metaIndex ; ++ i )
ourIndex += Meta -> Fields [ i ]. ArraySize ;
return ourIndex ;
}
2017-03-08 18:10:02 +01:00
DB2FileSource ::~ DB2FileSource ()
{
}
class DB2FileLoaderImpl
{
public :
virtual ~ DB2FileLoaderImpl () { }
2018-03-16 18:44:57 +01:00
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 ;
2019-06-08 13:19:48 +02:00
virtual void SkipEncryptedSection ( uint32 section ) = 0 ;
2018-03-16 18:44:57 +01:00
virtual bool LoadTableData ( DB2FileSource * source , uint32 section ) = 0 ;
virtual bool LoadCatalogData ( DB2FileSource * source , uint32 section ) = 0 ;
2019-08-11 12:17:33 +02:00
virtual void SetAdditionalData ( std :: vector < uint32 > idTable , std :: vector < DB2RecordCopy > copyTable , std :: vector < std :: vector < DB2IndexData >> parentIndexes ) = 0 ;
2017-03-08 18:10:02 +01:00
virtual char * AutoProduceData ( uint32 & count , char **& indexTable , std :: vector < char *>& stringPool ) = 0 ;
2018-05-12 16:24:41 +02:00
virtual char * AutoProduceStrings ( char ** indexTable , uint32 indexTableSize , uint32 locale ) = 0 ;
2017-03-08 18:10:02 +01:00
virtual void AutoProduceRecordCopies ( uint32 records , char ** indexTable , char * dataTable ) = 0 ;
virtual DB2Record GetRecord ( uint32 recordNumber ) const = 0 ;
virtual DB2RecordCopy GetRecordCopy ( uint32 copyNumber ) const = 0 ;
virtual uint32 GetRecordCount () const = 0 ;
virtual uint32 GetRecordCopyCount () const = 0 ;
virtual uint32 GetMaxId () const = 0 ;
2017-04-17 00:03:44 +02:00
virtual DB2FileLoadInfo const * GetLoadInfo () const = 0 ;
2020-05-10 15:29:47 +02:00
virtual DB2SectionHeader & GetSection ( uint32 section ) const = 0 ;
2018-03-16 18:44:57 +01:00
virtual bool IsSignedField ( uint32 field ) const = 0 ;
2017-03-08 18:10:02 +01:00
private :
friend class DB2Record ;
2019-06-08 13:19:48 +02:00
virtual unsigned char const * GetRawRecordData ( uint32 recordNumber , uint32 const * section ) const = 0 ;
2018-02-18 16:32:03 +01:00
virtual uint32 RecordGetId ( uint8 const * record , uint32 recordIndex ) const = 0 ;
virtual uint8 RecordGetUInt8 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const = 0 ;
virtual uint16 RecordGetUInt16 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const = 0 ;
virtual uint32 RecordGetUInt32 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const = 0 ;
virtual int32 RecordGetInt32 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const = 0 ;
virtual uint64 RecordGetUInt64 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const = 0 ;
virtual float RecordGetFloat ( uint8 const * record , uint32 field , uint32 arrayIndex ) const = 0 ;
virtual char const * RecordGetString ( uint8 const * record , uint32 field , uint32 arrayIndex ) const = 0 ;
2017-03-08 18:10:02 +01:00
virtual std :: size_t * RecordCreateDetachedFieldOffsets ( std :: size_t * oldOffsets ) const = 0 ;
virtual void RecordDestroyFieldOffsets ( std :: size_t *& fieldOffsets ) const = 0 ;
};
class DB2FileLoaderRegularImpl final : public DB2FileLoaderImpl
{
public :
2018-02-18 16:32:03 +01:00
DB2FileLoaderRegularImpl ( char const * fileName , DB2FileLoadInfo const * loadInfo , DB2Header const * header );
2017-03-08 18:10:02 +01:00
~ DB2FileLoaderRegularImpl ();
2018-03-16 18:44:57 +01:00
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 ;
2019-06-08 13:19:48 +02:00
void SkipEncryptedSection ( uint32 /*section*/ ) override { }
2018-03-16 18:44:57 +01:00
bool LoadTableData ( DB2FileSource * source , uint32 section ) override ;
bool LoadCatalogData ( DB2FileSource * /*source*/ , uint32 /*section*/ ) override { return true ; }
2019-08-11 12:17:33 +02:00
void SetAdditionalData ( std :: vector < uint32 > idTable , std :: vector < DB2RecordCopy > copyTable , std :: vector < std :: vector < DB2IndexData >> parentIndexes ) override ;
2017-03-08 18:10:02 +01:00
char * AutoProduceData ( uint32 & count , char **& indexTable , std :: vector < char *>& stringPool ) override ;
2018-05-12 16:24:41 +02:00
char * AutoProduceStrings ( char ** indexTable , uint32 indexTableSize , uint32 locale ) override ;
2017-03-08 18:10:02 +01:00
void AutoProduceRecordCopies ( uint32 records , char ** indexTable , char * dataTable ) override ;
DB2Record GetRecord ( uint32 recordNumber ) const override ;
DB2RecordCopy GetRecordCopy ( uint32 copyNumber ) const override ;
uint32 GetRecordCount () const override ;
uint32 GetRecordCopyCount () const override ;
uint32 GetMaxId () const override ;
2017-04-17 00:03:44 +02:00
DB2FileLoadInfo const * GetLoadInfo () const override ;
2020-05-10 15:29:47 +02:00
DB2SectionHeader & GetSection ( uint32 section ) const override ;
2018-03-16 18:44:57 +01:00
bool IsSignedField ( uint32 field ) const override ;
2017-03-08 18:10:02 +01:00
private :
2018-02-18 16:32:03 +01:00
void FillParentLookup ( char * dataTable );
2019-06-08 13:19:48 +02:00
uint32 GetRecordSection ( uint32 recordNumber ) const ;
unsigned char const * GetRawRecordData ( uint32 recordNumber , uint32 const * section ) const override ;
2018-02-18 16:32:03 +01:00
uint32 RecordGetId ( uint8 const * record , uint32 recordIndex ) const override ;
uint8 RecordGetUInt8 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const override ;
uint16 RecordGetUInt16 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const override ;
uint32 RecordGetUInt32 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const override ;
int32 RecordGetInt32 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const override ;
uint64 RecordGetUInt64 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const override ;
float RecordGetFloat ( uint8 const * record , uint32 field , uint32 arrayIndex ) const override ;
char const * RecordGetString ( uint8 const * record , uint32 field , uint32 arrayIndex ) const override ;
template < typename T >
T RecordGetVarInt ( uint8 const * record , uint32 field , uint32 arrayIndex ) const ;
uint64 RecordGetPackedValue ( uint8 const * packedRecordData , uint32 bitWidth , uint32 bitOffset ) const ;
2017-03-08 18:10:02 +01:00
uint16 GetFieldOffset ( uint32 field ) const ;
std :: size_t * RecordCreateDetachedFieldOffsets ( std :: size_t * oldOffsets ) const override ;
void RecordDestroyFieldOffsets ( std :: size_t *& fieldOffsets ) const override ;
2018-02-18 16:32:03 +01:00
char const * _fileName ;
2017-03-08 18:10:02 +01:00
DB2FileLoadInfo const * _loadInfo ;
DB2Header const * _header ;
2018-02-18 16:32:03 +01:00
std :: unique_ptr < uint8 [] > _data ;
uint8 * _stringTable ;
2018-03-16 18:44:57 +01:00
std :: unique_ptr < DB2SectionHeader [] > _sections ;
2018-02-18 16:32:03 +01:00
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 ;
2018-03-16 18:44:57 +01:00
std :: vector < uint32 > _idTable ;
std :: vector < DB2RecordCopy > _copyTable ;
2019-08-11 12:17:33 +02:00
std :: vector < std :: vector < DB2IndexData >> _parentIndexes ;
2017-03-08 18:10:02 +01:00
};
class DB2FileLoaderSparseImpl final : public DB2FileLoaderImpl
{
public :
2019-06-08 13:19:48 +02:00
DB2FileLoaderSparseImpl ( char const * fileName , DB2FileLoadInfo const * loadInfo , DB2Header const * header , DB2FileSource * source );
2017-03-08 18:10:02 +01:00
~ DB2FileLoaderSparseImpl ();
2018-03-16 18:44:57 +01:00
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 ;
2019-06-08 13:19:48 +02:00
void SkipEncryptedSection ( uint32 section ) override ;
2019-06-08 17:57:58 +02:00
bool LoadTableData ( DB2FileSource * /*source*/ , uint32 /*section*/ ) override { return true ; }
2018-03-16 18:44:57 +01:00
bool LoadCatalogData ( DB2FileSource * source , uint32 section ) override ;
2019-08-11 12:17:33 +02:00
void SetAdditionalData ( std :: vector < uint32 > idTable , std :: vector < DB2RecordCopy > copyTable , std :: vector < std :: vector < DB2IndexData >> parentIndexes ) override ;
2017-03-08 18:10:02 +01:00
char * AutoProduceData ( uint32 & records , char **& indexTable , std :: vector < char *>& stringPool ) override ;
2018-05-12 16:24:41 +02:00
char * AutoProduceStrings ( char ** indexTable , uint32 indexTableSize , uint32 locale ) override ;
2019-08-11 12:17:33 +02:00
void AutoProduceRecordCopies ( uint32 records , char ** indexTable , char * dataTable ) override ;
2017-03-08 18:10:02 +01:00
DB2Record GetRecord ( uint32 recordNumber ) const override ;
DB2RecordCopy GetRecordCopy ( uint32 copyNumber ) const override ;
uint32 GetRecordCount () const override ;
uint32 GetRecordCopyCount () const override ;
uint32 GetMaxId () const override ;
2017-04-17 00:03:44 +02:00
DB2FileLoadInfo const * GetLoadInfo () const override ;
2020-05-10 15:29:47 +02:00
DB2SectionHeader & GetSection ( uint32 section ) const override ;
2018-03-16 18:44:57 +01:00
bool IsSignedField ( uint32 field ) const override ;
2017-03-08 18:10:02 +01:00
private :
2019-06-08 13:19:48 +02:00
void FillParentLookup ( char * dataTable );
uint32 GetRecordSection ( uint32 recordNumber ) const ;
unsigned char const * GetRawRecordData ( uint32 recordNumber , uint32 const * section ) const override ;
2018-02-18 16:32:03 +01:00
uint32 RecordGetId ( uint8 const * record , uint32 recordIndex ) const override ;
uint8 RecordGetUInt8 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const override ;
uint16 RecordGetUInt16 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const override ;
uint32 RecordGetUInt32 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const override ;
int32 RecordGetInt32 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const override ;
uint64 RecordGetUInt64 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const override ;
float RecordGetFloat ( uint8 const * record , uint32 field , uint32 arrayIndex ) const override ;
char const * RecordGetString ( uint8 const * record , uint32 field , uint32 arrayIndex ) const override ;
uint32 RecordGetVarInt ( uint8 const * record , uint32 field , uint32 arrayIndex , bool isSigned ) const ;
2017-03-08 18:10:02 +01:00
uint16 GetFieldOffset ( uint32 field , uint32 arrayIndex ) const ;
uint16 GetFieldSize ( uint32 field ) const ;
std :: size_t * RecordCreateDetachedFieldOffsets ( std :: size_t * oldOffsets ) const override ;
void RecordDestroyFieldOffsets ( std :: size_t *& fieldOffsets ) const override ;
2018-02-18 16:32:03 +01:00
void CalculateAndStoreFieldOffsets ( uint8 const * rawRecord ) const ;
2017-03-08 18:10:02 +01:00
#pragma pack(push, 1)
#pragma pack(pop)
2018-02-18 16:32:03 +01:00
char const * _fileName ;
2017-03-08 18:10:02 +01:00
DB2FileLoadInfo const * _loadInfo ;
DB2Header const * _header ;
2019-06-08 13:19:48 +02:00
DB2FileSource * const _source ;
std :: size_t _totalRecordSize ;
uint16 _maxRecordSize ;
std :: unique_ptr < uint8 [] > _recordBuffer ;
2018-03-16 18:44:57 +01:00
std :: unique_ptr < DB2SectionHeader [] > _sections ;
2018-02-18 16:32:03 +01:00
std :: unique_ptr < DB2FieldEntry [] > _fields ;
std :: unique_ptr < std :: size_t [] > _fieldAndArrayOffsets ;
2019-06-08 13:19:48 +02:00
std :: vector < uint32 > _catalogIds ;
std :: vector < DB2CatalogEntry > _catalog ;
std :: vector < DB2RecordCopy > _copyTable ;
2019-08-11 12:17:33 +02:00
std :: vector < std :: vector < DB2IndexData >> _parentIndexes ;
2017-03-08 18:10:02 +01:00
};
2018-02-18 16:32:03 +01:00
DB2FileLoaderRegularImpl :: DB2FileLoaderRegularImpl ( char const * fileName , DB2FileLoadInfo const * loadInfo , DB2Header const * header ) :
_fileName ( fileName ),
_loadInfo ( loadInfo ),
_header ( header ),
_stringTable ( nullptr )
2017-03-08 18:10:02 +01:00
{
}
2018-03-16 18:44:57 +01:00
void DB2FileLoaderRegularImpl :: 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 )
2017-03-08 18:10:02 +01:00
{
2018-03-16 18:44:57 +01:00
_sections = std :: move ( sections );
_columnMeta = std :: move ( columnMeta );
_palletValues = std :: move ( palletValues );
_palletArrayValues = std :: move ( palletArrayValues );
_commonValues = std :: move ( commonValues );
}
bool DB2FileLoaderRegularImpl :: LoadTableData ( DB2FileSource * source , uint32 section )
{
if ( ! _data )
{
2020-06-23 08:54:12 +02:00
_data = std :: make_unique < uint8 [] > ( _header -> RecordSize * _header -> RecordCount + _header -> StringTableSize + 8 );
2018-03-16 18:44:57 +01:00
_stringTable = & _data [ _header -> RecordSize * _header -> RecordCount ];
}
uint32 sectionDataStart = 0 ;
uint32 sectionStringTableStart = 0 ;
for ( uint32 i = 0 ; i < section ; ++ i )
{
sectionDataStart += _header -> RecordSize * _sections [ i ]. RecordCount ;
sectionStringTableStart += _sections [ i ]. StringTableSize ;
}
if ( _sections [ section ]. RecordCount && ! source -> Read ( & _data [ sectionDataStart ], _header -> RecordSize * _sections [ section ]. RecordCount ))
return false ;
if ( _sections [ section ]. StringTableSize && ! source -> Read ( & _stringTable [ sectionStringTableStart ], _sections [ section ]. StringTableSize ))
return false ;
return true ;
2018-02-18 16:32:03 +01:00
}
2017-04-06 23:39:34 +02:00
2019-08-11 12:17:33 +02:00
void DB2FileLoaderRegularImpl :: SetAdditionalData ( std :: vector < uint32 > idTable , std :: vector < DB2RecordCopy > copyTable , std :: vector < std :: vector < DB2IndexData >> parentIndexes )
2018-02-18 16:32:03 +01:00
{
_idTable = std :: move ( idTable );
_copyTable = std :: move ( copyTable );
_parentIndexes = std :: move ( parentIndexes );
2017-03-08 18:10:02 +01:00
}
DB2FileLoaderRegularImpl ::~ DB2FileLoaderRegularImpl ()
{
}
static char const * const nullStr = "" ;
char * DB2FileLoaderRegularImpl :: AutoProduceData ( uint32 & records , char **& indexTable , std :: vector < char *>& stringPool )
{
//get struct size and index pos
uint32 recordsize = _loadInfo -> Meta -> GetRecordSize ();
uint32 maxi = GetMaxId () + 1 ;
using index_entry_t = char * ;
records = maxi ;
indexTable = new index_entry_t [ maxi ];
memset ( indexTable , 0 , maxi * sizeof ( index_entry_t ));
2018-03-16 18:44:57 +01:00
char * dataTable = new char [( _header -> RecordCount + _copyTable . size ()) * recordsize ];
2017-03-08 18:10:02 +01:00
// we store flat holders pool as single memory block
std :: size_t stringFields = _loadInfo -> GetStringFieldCount ( false );
std :: size_t localizedStringFields = _loadInfo -> GetStringFieldCount ( true );
// each string field at load have array of string for each locale
std :: size_t stringHoldersRecordPoolSize = localizedStringFields * sizeof ( LocalizedString ) + ( stringFields - localizedStringFields ) * sizeof ( char * );
char * stringHoldersPool = nullptr ;
if ( stringFields )
{
std :: size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * _header -> RecordCount ;
stringHoldersPool = new char [ stringHoldersPoolSize ];
stringPool . push_back ( stringHoldersPool );
// DB2 strings expected to have at least empty string
for ( std :: size_t i = 0 ; i < stringHoldersPoolSize / sizeof ( char * ); ++ i )
(( char const ** ) stringHoldersPool )[ i ] = nullStr ;
}
uint32 offset = 0 ;
2019-06-08 13:19:48 +02:00
uint32 y = 0 ;
2017-03-08 18:10:02 +01:00
2019-06-08 13:19:48 +02:00
for ( uint32 section = 0 ; section < _header -> SectionCount ; ++ section )
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
DB2SectionHeader const & sectionHeader = GetSection ( section );
if ( sectionHeader . TactId )
{
offset += recordsize * sectionHeader . RecordCount ;
y += sectionHeader . RecordCount ;
2017-03-08 18:10:02 +01:00
continue ;
2019-06-08 13:19:48 +02:00
}
2017-03-08 18:10:02 +01:00
2019-06-08 13:19:48 +02:00
for ( uint32 sr = 0 ; sr < sectionHeader . RecordCount ; ++ sr , ++ y )
{
unsigned char const * rawRecord = GetRawRecordData ( y , & section );
if ( ! rawRecord )
continue ;
2017-03-08 18:10:02 +01:00
2019-06-08 13:19:48 +02:00
uint32 indexVal = RecordGetId ( rawRecord , y );
2017-03-08 18:10:02 +01:00
2019-06-08 13:19:48 +02:00
indexTable [ indexVal ] = & dataTable [ offset ];
uint32 fieldIndex = 0 ;
if ( ! _loadInfo -> Meta -> HasIndexFieldInData ())
{
* (( uint32 * )( & dataTable [ offset ])) = indexVal ;
offset += 4 ;
++ fieldIndex ;
}
2017-03-08 18:10:02 +01:00
2019-06-08 13:19:48 +02:00
uint32 stringFieldOffset = 0 ;
2017-03-08 18:10:02 +01:00
2019-06-08 13:19:48 +02:00
for ( uint32 x = 0 ; x < _header -> FieldCount ; ++ x )
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
for ( uint32 z = 0 ; z < _loadInfo -> Meta -> Fields [ x ]. ArraySize ; ++ z )
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
switch ( _loadInfo -> TypesString [ fieldIndex ])
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
case FT_FLOAT :
* (( float * )( & dataTable [ offset ])) = RecordGetFloat ( rawRecord , x , z );
offset += 4 ;
break ;
case FT_INT :
* (( uint32 * )( & dataTable [ offset ])) = RecordGetVarInt < uint32 > ( rawRecord , x , z );
offset += 4 ;
break ;
case FT_BYTE :
* (( uint8 * )( & dataTable [ offset ])) = RecordGetUInt8 ( rawRecord , x , z );
offset += 1 ;
break ;
case FT_SHORT :
* (( uint16 * )( & dataTable [ offset ])) = RecordGetUInt16 ( rawRecord , x , z );
offset += 2 ;
break ;
case FT_LONG :
* (( uint64 * )( & dataTable [ offset ])) = RecordGetUInt64 ( rawRecord , x , z );
offset += 8 ;
break ;
case FT_STRING :
case FT_STRING_NOT_LOCALIZED :
{
// init db2 string field slots by pointers to string holders
char const *** slot = ( char const *** )( & dataTable [ offset ]);
* slot = ( char const ** )( & stringHoldersPool [ stringHoldersRecordPoolSize * y + stringFieldOffset ]);
if ( _loadInfo -> TypesString [ fieldIndex ] == FT_STRING )
stringFieldOffset += sizeof ( LocalizedString );
else
stringFieldOffset += sizeof ( char * );
offset += sizeof ( char * );
break ;
}
default :
ASSERT ( false , "Unknown format character '%c' found in %s meta for field %s" ,
_loadInfo -> TypesString [ fieldIndex ], _fileName , _loadInfo -> Fields [ fieldIndex ]. Name );
break ;
2017-03-08 18:10:02 +01:00
}
2019-06-08 13:19:48 +02:00
++ fieldIndex ;
2017-03-08 18:10:02 +01:00
}
}
2017-04-06 23:39:34 +02:00
2019-06-08 13:19:48 +02:00
for ( uint32 x = _header -> FieldCount ; x < _loadInfo -> Meta -> FieldCount ; ++ x )
2017-04-06 23:39:34 +02:00
{
2019-06-08 13:19:48 +02:00
for ( uint32 z = 0 ; z < _loadInfo -> Meta -> Fields [ x ]. ArraySize ; ++ z )
2017-04-06 23:39:34 +02:00
{
2019-06-08 13:19:48 +02:00
switch ( _loadInfo -> TypesString [ fieldIndex ])
2017-04-06 23:39:34 +02:00
{
2019-06-08 13:19:48 +02:00
case FT_INT :
* (( uint32 * )( & dataTable [ offset ])) = 0 ;
offset += 4 ;
break ;
case FT_BYTE :
* (( uint8 * )( & dataTable [ offset ])) = 0 ;
offset += 1 ;
break ;
case FT_SHORT :
* (( uint16 * )( & dataTable [ offset ])) = 0 ;
offset += 2 ;
break ;
default :
2019-11-28 00:23:09 +01:00
ASSERT ( false , "Unknown format character '%c' found in %s meta for parent field %s" ,
2019-06-08 13:19:48 +02:00
_loadInfo -> TypesString [ fieldIndex ], _fileName , _loadInfo -> Fields [ fieldIndex ]. Name );
break ;
2017-04-06 23:39:34 +02:00
}
2019-06-08 13:19:48 +02:00
++ fieldIndex ;
2017-04-06 23:39:34 +02:00
}
}
}
2017-03-08 18:10:02 +01:00
}
2018-03-16 18:44:57 +01:00
if ( ! _parentIndexes . empty ())
2018-02-18 16:32:03 +01:00
FillParentLookup ( dataTable );
2017-04-06 23:39:34 +02:00
2017-03-08 18:10:02 +01:00
return dataTable ;
}
2018-05-12 16:24:41 +02:00
char * DB2FileLoaderRegularImpl :: AutoProduceStrings ( char ** indexTable , uint32 indexTableSize , uint32 locale )
2017-03-08 18:10:02 +01:00
{
if ( ! ( _header -> Locale & ( 1 << locale )))
{
char const * sep = "" ;
std :: ostringstream str ;
for ( uint32 i = 0 ; i < TOTAL_LOCALES ; ++ i )
{
if ( _header -> Locale & ( 1 << i ))
{
str << sep << localeNames [ i ];
sep = ", " ;
}
}
2018-02-18 16:32:03 +01:00
TC_LOG_ERROR ( "" , "Attempted to load %s which has locales %s as %s. Check if you placed your localized db2 files in correct directory." , _fileName , str . str (). c_str (), localeNames [ locale ]);
2017-03-08 18:10:02 +01:00
return nullptr ;
}
char * stringPool = new char [ _header -> StringTableSize ];
2018-02-18 16:32:03 +01:00
memcpy ( stringPool , _stringTable , _header -> StringTableSize );
2017-03-08 18:10:02 +01:00
2019-06-08 13:19:48 +02:00
uint32 y = 0 ;
for ( uint32 section = 0 ; section < _header -> SectionCount ; ++ section )
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
DB2SectionHeader const & sectionHeader = GetSection ( section );
if ( sectionHeader . TactId )
{
y += sectionHeader . RecordCount ;
2018-05-12 16:24:41 +02:00
continue ;
2019-06-08 13:19:48 +02:00
}
2018-05-12 16:24:41 +02:00
2019-06-08 13:19:48 +02:00
for ( uint32 sr = 0 ; sr < sectionHeader . RecordCount ; ++ sr , ++ y )
{
unsigned char const * rawRecord = GetRawRecordData ( y , & section );
if ( ! rawRecord )
continue ;
2018-05-12 16:24:41 +02:00
2019-06-08 13:19:48 +02:00
uint32 indexVal = RecordGetId ( rawRecord , y );
if ( indexVal >= indexTableSize )
continue ;
2018-05-12 16:24:41 +02:00
2019-06-08 13:19:48 +02:00
char * recordData = indexTable [ indexVal ];
2017-03-08 18:10:02 +01:00
2019-06-08 13:19:48 +02:00
uint32 offset = 0 ;
uint32 fieldIndex = 0 ;
if ( ! _loadInfo -> Meta -> HasIndexFieldInData ())
{
offset += 4 ;
++ fieldIndex ;
}
for ( uint32 x = 0 ; x < _loadInfo -> Meta -> FieldCount ; ++ x )
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
for ( uint32 z = 0 ; z < _loadInfo -> Meta -> Fields [ x ]. ArraySize ; ++ z )
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
switch ( _loadInfo -> TypesString [ fieldIndex ])
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
case FT_FLOAT :
case FT_INT :
offset += 4 ;
break ;
case FT_BYTE :
offset += 1 ;
break ;
case FT_SHORT :
offset += 2 ;
break ;
case FT_LONG :
offset += 8 ;
break ;
case FT_STRING :
{
// fill only not filled entries
LocalizedString * db2str = * ( LocalizedString * * )( & recordData [ offset ]);
if ( db2str -> Str [ locale ] == nullStr )
{
char const * st = RecordGetString ( rawRecord , x , z );
db2str -> Str [ locale ] = stringPool + ( st - ( char const * ) _stringTable );
}
offset += sizeof ( char * );
break ;
}
case FT_STRING_NOT_LOCALIZED :
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
char ** db2str = ( char ** )( & recordData [ offset ]);
2017-03-08 18:10:02 +01:00
char const * st = RecordGetString ( rawRecord , x , z );
2019-06-08 13:19:48 +02:00
* db2str = stringPool + ( st - ( char const * ) _stringTable );
offset += sizeof ( char * );
break ;
2017-03-08 18:10:02 +01:00
}
2019-06-08 13:19:48 +02:00
default :
ASSERT ( false , "Unknown format character '%c' found in %s meta for field %s" ,
_loadInfo -> TypesString [ fieldIndex ], _fileName , _loadInfo -> Fields [ fieldIndex ]. Name );
break ;
2017-03-08 18:10:02 +01:00
}
2019-06-08 13:19:48 +02:00
++ fieldIndex ;
2017-03-08 18:10:02 +01:00
}
}
}
}
return stringPool ;
}
void DB2FileLoaderRegularImpl :: AutoProduceRecordCopies ( uint32 records , char ** indexTable , char * dataTable )
{
uint32 recordsize = _loadInfo -> Meta -> GetRecordSize ();
uint32 offset = _header -> RecordCount * recordsize ;
2018-02-18 16:32:03 +01:00
uint32 idFieldOffset = _loadInfo -> Meta -> HasIndexFieldInData () ? GetFieldOffset ( _loadInfo -> Meta -> GetIndexField ()) : 0 ;
2017-03-08 18:10:02 +01:00
for ( uint32 c = 0 ; c < GetRecordCopyCount (); ++ c )
{
DB2RecordCopy copy = GetRecordCopy ( c );
if ( copy . SourceRowId && copy . SourceRowId < records && copy . NewRowId < records && indexTable [ copy . SourceRowId ])
{
indexTable [ copy . NewRowId ] = & dataTable [ offset ];
memcpy ( indexTable [ copy . NewRowId ], indexTable [ copy . SourceRowId ], recordsize );
2018-02-18 16:32:03 +01:00
* (( uint32 * )( & dataTable [ offset + idFieldOffset ])) = copy . NewRowId ;
2017-03-08 18:10:02 +01:00
offset += recordsize ;
}
}
}
2018-02-18 16:32:03 +01:00
void DB2FileLoaderRegularImpl :: FillParentLookup ( char * dataTable )
2017-04-06 23:39:34 +02:00
{
2018-02-18 16:32:03 +01:00
int32 parentIdOffset = _loadInfo -> Meta -> GetParentIndexFieldOffset ();
uint32 recordSize = _loadInfo -> Meta -> GetRecordSize ();
2019-08-11 12:17:33 +02:00
uint32 recordIndexOffset = 0 ;
for ( uint32 i = 0 ; i < _header -> SectionCount ; ++ i )
2017-04-06 23:39:34 +02:00
{
2019-08-11 12:17:33 +02:00
DB2SectionHeader const & section = GetSection ( i );
2019-10-26 23:58:29 +02:00
if ( ! section . TactId )
2017-04-06 23:39:34 +02:00
{
2019-10-26 23:58:29 +02:00
for ( std :: size_t j = 0 ; j < _parentIndexes [ i ][ 0 ]. Entries . size (); ++ j )
2019-08-11 12:17:33 +02:00
{
2019-10-26 23:58:29 +02:00
uint32 parentId = _parentIndexes [ i ][ 0 ]. Entries [ j ]. ParentId ;
char * recordData = & dataTable [( _parentIndexes [ i ][ 0 ]. Entries [ j ]. RecordIndex + recordIndexOffset ) * recordSize ];
switch ( _loadInfo -> Meta -> Fields [ _loadInfo -> Meta -> ParentIndexField ]. Type )
{
case FT_SHORT :
2019-11-28 00:23:09 +01:00
{
if ( _loadInfo -> Meta -> ParentIndexField >= int32 ( _loadInfo -> Meta -> FileFieldCount ))
{
// extra field at the end
* reinterpret_cast < uint32 *> ( & recordData [ parentIdOffset ]) = parentId ;
}
else
{
// in data block, must fit
ASSERT ( parentId <= 0xFFFF , "ParentId value %u does not fit into uint16 field (%s in %s)" ,
parentId , _loadInfo -> Fields [ _loadInfo -> GetFieldIndexByMetaIndex ( _loadInfo -> Meta -> ParentIndexField )]. Name , _fileName );
* reinterpret_cast < uint16 *> ( & recordData [ parentIdOffset ]) = parentId ;
}
2019-10-26 23:58:29 +02:00
break ;
2019-11-28 00:23:09 +01:00
}
2019-10-26 23:58:29 +02:00
case FT_BYTE :
2019-11-28 00:23:09 +01:00
{
if ( _loadInfo -> Meta -> ParentIndexField >= int32 ( _loadInfo -> Meta -> FileFieldCount ))
{
// extra field at the end
* reinterpret_cast < uint32 *> ( & recordData [ parentIdOffset ]) = parentId ;
}
else
{
// in data block, must fit
ASSERT ( parentId <= 0xFF , "ParentId value %u does not fit into uint8 field (%s in %s)" ,
parentId , _loadInfo -> Fields [ _loadInfo -> GetFieldIndexByMetaIndex ( _loadInfo -> Meta -> ParentIndexField )]. Name , _fileName );
* reinterpret_cast < uint8 *> ( & recordData [ parentIdOffset ]) = parentId ;
}
2019-10-26 23:58:29 +02:00
break ;
2019-11-28 00:23:09 +01:00
}
2019-10-26 23:58:29 +02:00
case FT_INT :
* reinterpret_cast < uint32 *> ( & recordData [ parentIdOffset ]) = parentId ;
break ;
default :
ASSERT ( false , "Unhandled parent id type '%c' found in %s" , _loadInfo -> Meta -> Fields [ _loadInfo -> Meta -> ParentIndexField ]. Type , _fileName );
break ;
}
2019-08-11 12:17:33 +02:00
}
2017-04-06 23:39:34 +02:00
}
2019-08-11 12:17:33 +02:00
recordIndexOffset += section . RecordCount ;
2017-04-06 23:39:34 +02:00
}
}
2017-03-08 18:10:02 +01:00
DB2Record DB2FileLoaderRegularImpl :: GetRecord ( uint32 recordNumber ) const
{
return DB2Record ( * this , recordNumber , nullptr );
}
DB2RecordCopy DB2FileLoaderRegularImpl :: GetRecordCopy ( uint32 copyNumber ) const
{
if ( copyNumber >= GetRecordCopyCount ())
return DB2RecordCopy {};
2018-02-18 16:32:03 +01:00
return _copyTable [ copyNumber ];
2017-03-08 18:10:02 +01:00
}
uint32 DB2FileLoaderRegularImpl :: GetRecordCount () const
{
return _header -> RecordCount ;
}
uint32 DB2FileLoaderRegularImpl :: GetRecordCopyCount () const
{
2018-03-16 18:44:57 +01:00
return _copyTable . size ();
2017-03-08 18:10:02 +01:00
}
2019-06-08 13:19:48 +02:00
uint32 DB2FileLoaderRegularImpl :: GetRecordSection ( uint32 recordNumber ) const
{
uint32 section = 0 ;
for (; section < _header -> SectionCount ; ++ section )
{
DB2SectionHeader const & sectionHeader = GetSection ( section );
if ( recordNumber < sectionHeader . RecordCount )
break ;
recordNumber -= sectionHeader . RecordCount ;
}
return section ;
}
unsigned char const * DB2FileLoaderRegularImpl :: GetRawRecordData ( uint32 recordNumber , uint32 const * section ) const
2017-03-08 18:10:02 +01:00
{
if ( recordNumber >= _header -> RecordCount )
return nullptr ;
2019-06-08 13:19:48 +02:00
if ( GetSection ( section ? * section : GetRecordSection ( recordNumber )). TactId )
return nullptr ;
2018-02-18 16:32:03 +01:00
return & _data [ recordNumber * _header -> RecordSize ];
2017-03-08 18:10:02 +01:00
}
2018-02-18 16:32:03 +01:00
uint32 DB2FileLoaderRegularImpl :: RecordGetId ( uint8 const * record , uint32 recordIndex ) const
2017-03-08 18:10:02 +01:00
{
if ( _loadInfo -> Meta -> HasIndexFieldInData ())
2018-02-18 16:32:03 +01:00
return RecordGetVarInt < uint32 > ( record , _loadInfo -> Meta -> GetIndexField (), 0 );
2017-03-08 18:10:02 +01:00
2018-02-18 16:32:03 +01:00
return _idTable [ recordIndex ];
2017-03-08 18:10:02 +01:00
}
2018-02-18 16:32:03 +01:00
uint8 DB2FileLoaderRegularImpl :: RecordGetUInt8 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const
2017-03-08 18:10:02 +01:00
{
2018-02-18 16:32:03 +01:00
return RecordGetVarInt < uint8 > ( record , field , arrayIndex );
2017-03-08 18:10:02 +01:00
}
2018-02-18 16:32:03 +01:00
uint16 DB2FileLoaderRegularImpl :: RecordGetUInt16 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const
2017-03-08 18:10:02 +01:00
{
2018-02-18 16:32:03 +01:00
return RecordGetVarInt < uint16 > ( record , field , arrayIndex );
2017-03-08 18:10:02 +01:00
}
2018-02-18 16:32:03 +01:00
uint32 DB2FileLoaderRegularImpl :: RecordGetUInt32 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const
2017-03-08 18:10:02 +01:00
{
2018-02-18 16:32:03 +01:00
return RecordGetVarInt < uint32 > ( record , field , arrayIndex );
2017-03-08 18:10:02 +01:00
}
2018-02-18 16:32:03 +01:00
int32 DB2FileLoaderRegularImpl :: RecordGetInt32 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const
2017-03-08 18:10:02 +01:00
{
2018-02-18 16:32:03 +01:00
return RecordGetVarInt < int32 > ( record , field , arrayIndex );
2017-03-08 18:10:02 +01:00
}
2018-02-18 16:32:03 +01:00
uint64 DB2FileLoaderRegularImpl :: RecordGetUInt64 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const
2017-03-08 18:10:02 +01:00
{
2018-02-18 16:32:03 +01:00
return RecordGetVarInt < uint64 > ( record , field , arrayIndex );
2017-03-08 18:10:02 +01:00
}
2018-02-18 16:32:03 +01:00
float DB2FileLoaderRegularImpl :: RecordGetFloat ( uint8 const * record , uint32 field , uint32 arrayIndex ) const
2017-03-08 18:10:02 +01:00
{
2018-02-18 16:32:03 +01:00
return RecordGetVarInt < float > ( record , field , arrayIndex );
}
char const * DB2FileLoaderRegularImpl :: RecordGetString ( uint8 const * record , uint32 field , uint32 arrayIndex ) const
{
2018-03-16 18:44:57 +01:00
uint32 fieldOffset = GetFieldOffset ( field ) + sizeof ( uint32 ) * arrayIndex ;
2018-02-18 16:32:03 +01:00
uint32 stringOffset = RecordGetVarInt < uint32 > ( record , field , arrayIndex );
2018-03-16 18:44:57 +01:00
ASSERT ( stringOffset < _header -> RecordSize * _header -> RecordCount + _header -> StringTableSize );
return reinterpret_cast < char const *> ( record + fieldOffset + stringOffset );
2017-03-08 18:10:02 +01:00
}
2018-02-18 16:32:03 +01:00
template < typename T >
T DB2FileLoaderRegularImpl :: RecordGetVarInt ( uint8 const * record , uint32 field , uint32 arrayIndex ) const
2017-03-08 18:10:02 +01:00
{
ASSERT ( field < _header -> FieldCount );
2018-03-16 18:44:57 +01:00
DB2ColumnCompression compressionType = _columnMeta ? _columnMeta [ field ]. CompressionType : DB2ColumnCompression :: None ;
switch ( compressionType )
2018-02-18 16:32:03 +01:00
{
case DB2ColumnCompression :: None :
{
T val = * reinterpret_cast < T const *> ( record + GetFieldOffset ( field ) + sizeof ( T ) * arrayIndex );
EndianConvert ( val );
return val ;
}
case DB2ColumnCompression :: Immediate :
{
ASSERT ( arrayIndex == 0 );
uint64 immediateValue = RecordGetPackedValue ( record + GetFieldOffset ( field ),
_columnMeta [ field ]. CompressionData . immediate . BitWidth , _columnMeta [ field ]. CompressionData . immediate . BitOffset );
EndianConvert ( immediateValue );
T value ;
memcpy ( & value , & immediateValue , std :: min ( sizeof ( T ), sizeof ( immediateValue )));
return value ;
}
case DB2ColumnCompression :: CommonData :
{
uint32 id = RecordGetId ( record , ( _data . get () - record ) / _header -> RecordSize );
T value ;
auto valueItr = _commonValues [ field ]. find ( id );
if ( valueItr != _commonValues [ field ]. end ())
memcpy ( & value , & valueItr -> second , std :: min ( sizeof ( T ), sizeof ( uint32 )));
else
memcpy ( & value , & _columnMeta [ field ]. CompressionData . commonData . Value , std :: min ( sizeof ( T ), sizeof ( uint32 )));
return value ;
}
case DB2ColumnCompression :: Pallet :
{
ASSERT ( arrayIndex == 0 );
uint64 palletIndex = RecordGetPackedValue ( record + GetFieldOffset ( field ),
_columnMeta [ field ]. CompressionData . pallet . BitWidth , _columnMeta [ field ]. CompressionData . pallet . BitOffset );
EndianConvert ( palletIndex );
uint32 palletValue = _palletValues [ field ][ palletIndex ]. Value ;
EndianConvert ( palletValue );
T value ;
memcpy ( & value , & palletValue , std :: min ( sizeof ( T ), sizeof ( palletValue )));
return value ;
}
case DB2ColumnCompression :: PalletArray :
{
uint64 palletIndex = RecordGetPackedValue ( record + GetFieldOffset ( field ),
_columnMeta [ field ]. CompressionData . pallet . BitWidth , _columnMeta [ field ]. CompressionData . pallet . BitOffset );
EndianConvert ( palletIndex );
uint32 palletValue = _palletArrayValues [ field ][ palletIndex * _columnMeta [ field ]. CompressionData . pallet . ArraySize + arrayIndex ]. Value ;
EndianConvert ( palletValue );
T value ;
memcpy ( & value , & palletValue , std :: min ( sizeof ( T ), sizeof ( palletValue )));
return value ;
}
2018-03-16 18:44:57 +01:00
case DB2ColumnCompression :: SignedImmediate :
{
ASSERT ( arrayIndex == 0 );
uint64 immediateValue = RecordGetPackedValue ( record + GetFieldOffset ( field ),
_columnMeta [ field ]. CompressionData . immediate . BitWidth , _columnMeta [ field ]. CompressionData . immediate . BitOffset );
EndianConvert ( immediateValue );
uint64 mask = UI64LIT ( 1 ) << ( _columnMeta [ field ]. CompressionData . immediate . BitWidth - 1 );
immediateValue = ( immediateValue ^ mask ) - mask ;
T value ;
memcpy ( & value , & immediateValue , std :: min ( sizeof ( T ), sizeof ( immediateValue )));
return value ;
}
2018-02-18 16:32:03 +01:00
default :
ASSERT ( false , "Unhandled compression type %u in %s" , uint32 ( _columnMeta [ field ]. CompressionType ), _fileName );
break ;
}
2017-03-08 18:10:02 +01:00
2018-02-18 16:32:03 +01:00
return 0 ;
2017-03-08 18:10:02 +01:00
}
2018-02-18 16:32:03 +01:00
uint64 DB2FileLoaderRegularImpl :: RecordGetPackedValue ( uint8 const * packedRecordData , uint32 bitWidth , uint32 bitOffset ) const
2017-03-08 18:10:02 +01:00
{
2018-02-18 16:32:03 +01:00
uint32 bitsToRead = bitOffset & 7 ;
return * reinterpret_cast < uint64 const *> ( packedRecordData ) << ( 64 - bitsToRead - bitWidth ) >> ( 64 - bitWidth );
2017-03-08 18:10:02 +01:00
}
2018-02-18 16:32:03 +01:00
uint16 DB2FileLoaderRegularImpl :: GetFieldOffset ( uint32 field ) const
2017-03-08 18:10:02 +01:00
{
ASSERT ( field < _header -> FieldCount );
2018-03-16 18:44:57 +01:00
DB2ColumnCompression compressionType = _columnMeta ? _columnMeta [ field ]. CompressionType : DB2ColumnCompression :: None ;
switch ( compressionType )
2018-02-18 16:32:03 +01:00
{
case DB2ColumnCompression :: None :
return _columnMeta [ field ]. BitOffset / 8 ;
case DB2ColumnCompression :: Immediate :
2018-03-16 18:44:57 +01:00
case DB2ColumnCompression :: SignedImmediate :
2018-02-18 16:32:03 +01:00
return _columnMeta [ field ]. CompressionData . immediate . BitOffset / 8 + _header -> PackedDataOffset ;
case DB2ColumnCompression :: CommonData :
return 0xFFFF ;
case DB2ColumnCompression :: Pallet :
case DB2ColumnCompression :: PalletArray :
return _columnMeta [ field ]. CompressionData . pallet . BitOffset / 8 + _header -> PackedDataOffset ;
default :
ASSERT ( false , "Unhandled compression type %u in %s" , uint32 ( _columnMeta [ field ]. CompressionType ), _fileName );
break ;
}
return 0 ;
2017-03-08 18:10:02 +01:00
}
std :: size_t * DB2FileLoaderRegularImpl :: RecordCreateDetachedFieldOffsets ( std :: size_t * /*oldOffsets*/ ) const
{
return nullptr ;
}
void DB2FileLoaderRegularImpl :: RecordDestroyFieldOffsets ( std :: size_t *& /*fieldOffsets*/ ) const
{
}
uint32 DB2FileLoaderRegularImpl :: GetMaxId () const
{
uint32 maxId = 0 ;
for ( uint32 row = 0 ; row < _header -> RecordCount ; ++ row )
{
2019-06-08 13:19:48 +02:00
unsigned char const * rawRecord = GetRawRecordData ( row , nullptr );
if ( ! rawRecord )
continue ;
uint32 id = RecordGetId ( rawRecord , row );
2017-03-08 18:10:02 +01:00
if ( id > maxId )
maxId = id ;
}
for ( uint32 copy = 0 ; copy < GetRecordCopyCount (); ++ copy )
{
uint32 id = GetRecordCopy ( copy ). NewRowId ;
if ( id > maxId )
maxId = id ;
}
2019-06-08 13:19:48 +02:00
ASSERT ( maxId <= _header -> MaxId );
2017-03-08 18:10:02 +01:00
return maxId ;
}
2017-04-17 00:03:44 +02:00
DB2FileLoadInfo const * DB2FileLoaderRegularImpl :: GetLoadInfo () const
{
return _loadInfo ;
}
2020-05-10 15:29:47 +02:00
DB2SectionHeader & DB2FileLoaderRegularImpl :: GetSection ( uint32 section ) const
2018-03-16 18:44:57 +01:00
{
return _sections [ section ];
}
bool DB2FileLoaderRegularImpl :: IsSignedField ( uint32 field ) const
{
if ( field >= _header -> TotalFieldCount )
{
ASSERT ( field == _header -> TotalFieldCount );
ASSERT ( int32 ( field ) == _loadInfo -> Meta -> ParentIndexField );
return _loadInfo -> Meta -> IsSignedField ( field );
}
DB2ColumnCompression compressionType = _columnMeta ? _columnMeta [ field ]. CompressionType : DB2ColumnCompression :: None ;
switch ( compressionType )
{
case DB2ColumnCompression :: None :
case DB2ColumnCompression :: CommonData :
case DB2ColumnCompression :: Pallet :
case DB2ColumnCompression :: PalletArray :
return _loadInfo -> Meta -> IsSignedField ( field );
case DB2ColumnCompression :: SignedImmediate :
return field != uint32 ( _loadInfo -> Meta -> IndexField );
case DB2ColumnCompression :: Immediate :
return false ;
default :
ASSERT ( false , "Unhandled compression type %u in %s" , uint32 ( _columnMeta [ field ]. CompressionType ), _fileName );
break ;
}
return false ;
}
2019-06-08 13:19:48 +02:00
DB2FileLoaderSparseImpl :: DB2FileLoaderSparseImpl ( char const * fileName , DB2FileLoadInfo const * loadInfo , DB2Header const * header , DB2FileSource * source ) :
2018-02-18 16:32:03 +01:00
_fileName ( fileName ),
_loadInfo ( loadInfo ),
_header ( header ),
2019-06-08 13:19:48 +02:00
_source ( source ),
_totalRecordSize ( 0 ),
_maxRecordSize ( 0 ),
2020-06-23 08:54:12 +02:00
_fieldAndArrayOffsets ( loadInfo ? ( std :: make_unique < std :: size_t [] > ( loadInfo -> Meta -> FieldCount + loadInfo -> FieldCount - ( ! loadInfo -> Meta -> HasIndexFieldInData () ? 1 : 0 ))) : nullptr )
2017-03-08 18:10:02 +01:00
{
}
DB2FileLoaderSparseImpl ::~ DB2FileLoaderSparseImpl ()
{
}
2018-03-16 18:44:57 +01:00
void DB2FileLoaderSparseImpl :: 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*/ )
2017-03-08 18:10:02 +01:00
{
2018-03-16 18:44:57 +01:00
_sections = std :: move ( sections );
_fields = std :: move ( fields );
2018-02-18 16:32:03 +01:00
}
2017-03-08 18:10:02 +01:00
2019-06-08 13:19:48 +02:00
void DB2FileLoaderSparseImpl :: SkipEncryptedSection ( uint32 section )
2018-02-18 16:32:03 +01:00
{
2019-06-08 13:19:48 +02:00
_catalogIds . resize ( _catalogIds . size () + _sections [ section ]. CatalogDataCount );
_catalog . resize ( _catalog . size () + _sections [ section ]. CatalogDataCount );
2018-02-18 16:32:03 +01:00
}
2017-03-08 18:10:02 +01:00
2018-03-16 18:44:57 +01:00
bool DB2FileLoaderSparseImpl :: LoadCatalogData ( DB2FileSource * source , uint32 section )
2018-02-18 16:32:03 +01:00
{
2019-06-08 13:19:48 +02:00
source -> SetPosition ( _sections [ section ]. CatalogDataOffset );
std :: size_t oldSize = _catalog . size ();
_catalogIds . resize ( oldSize + _sections [ section ]. CatalogDataCount );
if ( ! source -> Read ( & _catalogIds [ oldSize ], sizeof ( uint32 ) * _sections [ section ]. CatalogDataCount ))
return false ;
if ( _sections [ section ]. CopyTableCount )
{
std :: size_t oldCopyTableSize = _copyTable . size ();
_copyTable . resize ( oldCopyTableSize + _sections [ section ]. CopyTableCount );
2019-11-03 20:02:10 +01:00
if ( ! source -> Read ( & _copyTable [ oldCopyTableSize ], sizeof ( DB2RecordCopy ) * _sections [ section ]. CopyTableCount ))
2019-06-08 13:19:48 +02:00
return false ;
}
_catalog . resize ( oldSize + _sections [ section ]. CatalogDataCount );
if ( ! source -> Read ( & _catalog [ oldSize ], sizeof ( DB2CatalogEntry ) * _sections [ section ]. CatalogDataCount ))
2018-03-16 18:44:57 +01:00
return false ;
2019-06-08 13:19:48 +02:00
for ( uint32 i = 0 ; i < _sections [ section ]. CatalogDataCount ; ++ i )
{
_totalRecordSize += _catalog [ oldSize + i ]. RecordSize ;
_maxRecordSize = std :: max ( _maxRecordSize , _catalog [ oldSize + i ]. RecordSize );
}
return true ;
}
2019-08-11 12:17:33 +02:00
void DB2FileLoaderSparseImpl :: SetAdditionalData ( std :: vector < uint32 > /*idTable*/ , std :: vector < DB2RecordCopy > /*copyTable*/ , std :: vector < std :: vector < DB2IndexData >> parentIndexes )
2019-06-08 13:19:48 +02:00
{
_parentIndexes = std :: move ( parentIndexes );
2020-06-23 08:54:12 +02:00
_recordBuffer = std :: make_unique < uint8 [] > ( _maxRecordSize );
2017-03-08 18:10:02 +01:00
}
char * DB2FileLoaderSparseImpl :: AutoProduceData ( uint32 & maxId , char **& indexTable , std :: vector < char *>& stringPool )
{
if ( _loadInfo -> Meta -> FieldCount != _header -> FieldCount )
2017-04-06 23:39:34 +02:00
return nullptr ;
2017-03-08 18:10:02 +01:00
//get struct size and index pos
uint32 recordsize = _loadInfo -> Meta -> GetRecordSize ();
2019-06-08 13:19:48 +02:00
uint32 records = _catalog . size ();
2017-03-08 18:10:02 +01:00
using index_entry_t = char * ;
maxId = _header -> MaxId + 1 ;
indexTable = new index_entry_t [ maxId ];
memset ( indexTable , 0 , maxId * sizeof ( index_entry_t ));
2019-06-08 13:19:48 +02:00
char * dataTable = new char [( records + _copyTable . size ()) * recordsize ];
2017-03-08 18:10:02 +01:00
// we store flat holders pool as single memory block
std :: size_t stringFields = _loadInfo -> GetStringFieldCount ( false );
std :: size_t localizedStringFields = _loadInfo -> GetStringFieldCount ( true );
// each string field at load have array of string for each locale
std :: size_t stringHoldersRecordPoolSize = localizedStringFields * sizeof ( LocalizedString ) + ( stringFields - localizedStringFields ) * sizeof ( char * );
std :: size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * records ;
char * stringHoldersPool = new char [ stringHoldersPoolSize ];
stringPool . push_back ( stringHoldersPool );
// DB2 strings expected to have at least empty string
for ( std :: size_t i = 0 ; i < stringHoldersPoolSize / sizeof ( char * ); ++ i )
(( char const ** ) stringHoldersPool )[ i ] = nullStr ;
2019-06-08 13:19:48 +02:00
char * stringTable = new char [ _totalRecordSize - records * (( recordsize - ( ! _loadInfo -> Meta -> HasIndexFieldInData () ? 4 : 0 )) - stringFields * sizeof ( char * ))];
memset ( stringTable , 0 , _totalRecordSize - records * (( recordsize - ( ! _loadInfo -> Meta -> HasIndexFieldInData () ? 4 : 0 )) - stringFields * sizeof ( char * )));
2017-03-08 18:10:02 +01:00
stringPool . push_back ( stringTable );
char * stringPtr = stringTable ;
uint32 offset = 0 ;
uint32 recordNum = 0 ;
2019-06-08 13:19:48 +02:00
uint32 y = 0 ;
2017-03-08 18:10:02 +01:00
2019-06-08 13:19:48 +02:00
for ( uint32 section = 0 ; section < _header -> SectionCount ; ++ section )
{
DB2SectionHeader const & sectionHeader = GetSection ( section );
if ( sectionHeader . TactId )
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
offset += recordsize * sectionHeader . RecordCount ;
y += sectionHeader . RecordCount ;
continue ;
2017-03-08 18:10:02 +01:00
}
2019-06-08 13:19:48 +02:00
for ( uint32 sr = 0 ; sr < sectionHeader . CatalogDataCount ; ++ sr , ++ y )
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
unsigned char const * rawRecord = GetRawRecordData ( y , & section );
if ( ! rawRecord )
continue ;
uint32 indexVal = _catalogIds [ y ];
indexTable [ indexVal ] = & dataTable [ offset ];
uint32 fieldIndex = 0 ;
if ( ! _loadInfo -> Meta -> HasIndexFieldInData ())
{
* (( uint32 * )( & dataTable [ offset ])) = indexVal ;
offset += 4 ;
++ fieldIndex ;
}
uint32 stringFieldOffset = 0 ;
for ( uint32 x = 0 ; x < _header -> FieldCount ; ++ x )
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
for ( uint32 z = 0 ; z < _loadInfo -> Meta -> Fields [ x ]. ArraySize ; ++ z )
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
switch ( _loadInfo -> TypesString [ fieldIndex ])
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
case FT_FLOAT :
* (( float * )( & dataTable [ offset ])) = RecordGetFloat ( rawRecord , x , z );
offset += 4 ;
break ;
case FT_INT :
* (( uint32 * )( & dataTable [ offset ])) = RecordGetVarInt ( rawRecord , x , z , _loadInfo -> Fields [ fieldIndex ]. IsSigned );
offset += 4 ;
break ;
case FT_BYTE :
* (( uint8 * )( & dataTable [ offset ])) = RecordGetUInt8 ( rawRecord , x , z );
offset += 1 ;
break ;
case FT_SHORT :
* (( uint16 * )( & dataTable [ offset ])) = RecordGetUInt16 ( rawRecord , x , z );
offset += 2 ;
break ;
case FT_LONG :
* (( uint64 * )( & dataTable [ offset ])) = RecordGetUInt64 ( rawRecord , x , z );
offset += 8 ;
break ;
case FT_STRING :
{
LocalizedString ** slot = ( LocalizedString * * )( & dataTable [ offset ]);
* slot = ( LocalizedString * )( & stringHoldersPool [ stringHoldersRecordPoolSize * recordNum + stringFieldOffset ]);
for ( uint32 locale = 0 ; locale < TOTAL_LOCALES ; ++ locale )
if ( _header -> Locale & ( 1 << locale ))
( * slot ) -> Str [ locale ] = stringPtr ;
strcpy ( stringPtr , RecordGetString ( rawRecord , x , z ));
stringPtr += strlen ( stringPtr ) + 1 ;
stringFieldOffset += sizeof ( LocalizedString );
offset += sizeof ( LocalizedString * );
break ;
}
case FT_STRING_NOT_LOCALIZED :
{
char const *** slot = ( char const *** )( & dataTable [ offset ]);
* slot = ( char const ** )( & stringHoldersPool [ stringHoldersRecordPoolSize * recordNum + stringFieldOffset ]);
** slot = stringPtr ;
strcpy ( stringPtr , RecordGetString ( rawRecord , x , z ));
stringPtr += strlen ( stringPtr ) + 1 ;
stringFieldOffset += sizeof ( char * );
offset += sizeof ( char * );
break ;
}
default :
ASSERT ( false , "Unknown format character '%c' found in %s meta for field %s" ,
_loadInfo -> TypesString [ fieldIndex ], _fileName , _loadInfo -> Fields [ fieldIndex ]. Name );
break ;
2017-03-08 18:10:02 +01:00
}
2019-06-08 13:19:48 +02:00
++ fieldIndex ;
}
}
for ( uint32 x = _header -> FieldCount ; x < _loadInfo -> Meta -> FieldCount ; ++ x )
{
for ( uint32 z = 0 ; z < _loadInfo -> Meta -> Fields [ x ]. ArraySize ; ++ z )
{
switch ( _loadInfo -> TypesString [ fieldIndex ])
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
case FT_INT :
* (( uint32 * )( & dataTable [ offset ])) = 0 ;
offset += 4 ;
break ;
case FT_BYTE :
* (( uint8 * )( & dataTable [ offset ])) = 0 ;
offset += 1 ;
break ;
case FT_SHORT :
* (( uint16 * )( & dataTable [ offset ])) = 0 ;
offset += 2 ;
break ;
default :
2019-11-28 00:23:09 +01:00
ASSERT ( false , "Unknown format character '%c' found in %s meta for parent field %s" ,
2019-06-08 13:19:48 +02:00
_loadInfo -> TypesString [ fieldIndex ], _fileName , _loadInfo -> Fields [ fieldIndex ]. Name );
break ;
2017-03-08 18:10:02 +01:00
}
2019-06-08 13:19:48 +02:00
++ fieldIndex ;
2017-03-08 18:10:02 +01:00
}
}
2019-06-08 13:19:48 +02:00
++ recordNum ;
}
2017-03-08 18:10:02 +01:00
}
return dataTable ;
}
2018-05-12 16:24:41 +02:00
char * DB2FileLoaderSparseImpl :: AutoProduceStrings ( char ** indexTable , uint32 indexTableSize , uint32 locale )
2017-03-08 18:10:02 +01:00
{
if ( _loadInfo -> Meta -> FieldCount != _header -> FieldCount )
return nullptr ;
if ( ! ( _header -> Locale & ( 1 << locale )))
{
char const * sep = "" ;
std :: ostringstream str ;
for ( uint32 i = 0 ; i < TOTAL_LOCALES ; ++ i )
{
if ( _header -> Locale & ( 1 << i ))
{
str << sep << localeNames [ i ];
sep = ", " ;
}
}
2018-02-18 16:32:03 +01:00
TC_LOG_ERROR ( "" , "Attempted to load %s which has locales %s as %s. Check if you placed your localized db2 files in correct directory." , _fileName , str . str (). c_str (), localeNames [ locale ]);
2017-03-08 18:10:02 +01:00
return nullptr ;
}
2019-06-08 13:19:48 +02:00
uint32 records = _catalog . size ();
2017-03-08 18:10:02 +01:00
uint32 recordsize = _loadInfo -> Meta -> GetRecordSize ();
std :: size_t stringFields = _loadInfo -> GetStringFieldCount ( true );
2019-06-08 13:19:48 +02:00
char * stringTable = new char [ _totalRecordSize - records * (( recordsize - ( ! _loadInfo -> Meta -> HasIndexFieldInData () ? 4 : 0 )) - stringFields * sizeof ( char * ))];
memset ( stringTable , 0 , _totalRecordSize - records * (( recordsize - ( ! _loadInfo -> Meta -> HasIndexFieldInData () ? 4 : 0 )) - stringFields * sizeof ( char * )));
2017-03-08 18:10:02 +01:00
char * stringPtr = stringTable ;
2019-06-08 13:19:48 +02:00
uint32 y = 0 ;
for ( uint32 section = 0 ; section < _header -> SectionCount ; ++ section )
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
DB2SectionHeader const & sectionHeader = GetSection ( section );
if ( sectionHeader . TactId )
{
y += sectionHeader . RecordCount ;
2017-03-08 18:10:02 +01:00
continue ;
2019-06-08 13:19:48 +02:00
}
2017-03-08 18:10:02 +01:00
2019-06-08 13:19:48 +02:00
for ( uint32 sr = 0 ; sr < sectionHeader . CatalogDataCount ; ++ sr , ++ y )
{
unsigned char const * rawRecord = GetRawRecordData ( y , & section );
if ( ! rawRecord )
continue ;
2018-05-12 16:24:41 +02:00
2019-06-08 13:19:48 +02:00
uint32 indexVal = _catalogIds [ y ];
if ( indexVal >= indexTableSize )
continue ;
2018-05-12 16:24:41 +02:00
2019-06-08 13:19:48 +02:00
char * recordData = indexTable [ indexVal ];
2017-03-08 18:10:02 +01:00
2019-06-08 13:19:48 +02:00
uint32 offset = 0 ;
uint32 fieldIndex = 0 ;
if ( ! _loadInfo -> Meta -> HasIndexFieldInData ())
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
offset += 4 ;
++ fieldIndex ;
}
for ( uint32 x = 0 ; x < _header -> FieldCount ; ++ x )
{
for ( uint32 z = 0 ; z < _loadInfo -> Meta -> Fields [ x ]. ArraySize ; ++ z )
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
switch ( _loadInfo -> TypesString [ fieldIndex ])
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
case FT_FLOAT :
offset += 4 ;
break ;
case FT_INT :
offset += 4 ;
break ;
case FT_BYTE :
offset += 1 ;
break ;
case FT_SHORT :
offset += 2 ;
break ;
case FT_LONG :
offset += 8 ;
break ;
case FT_STRING :
{
LocalizedString * db2str = * ( LocalizedString * * )( & recordData [ offset ]);
db2str -> Str [ locale ] = stringPtr ;
strcpy ( stringPtr , RecordGetString ( rawRecord , x , z ));
stringPtr += strlen ( stringPtr ) + 1 ;
offset += sizeof ( char * );
break ;
}
case FT_STRING_NOT_LOCALIZED :
offset += sizeof ( char * );
break ;
default :
ASSERT ( false , "Unknown format character '%c' found in %s meta for field %s" ,
_loadInfo -> TypesString [ fieldIndex ], _fileName , _loadInfo -> Fields [ fieldIndex ]. Name );
break ;
2017-03-08 18:10:02 +01:00
}
2019-06-08 13:19:48 +02:00
++ fieldIndex ;
2017-03-08 18:10:02 +01:00
}
}
}
}
return stringTable ;
}
2019-06-08 13:19:48 +02:00
void DB2FileLoaderSparseImpl :: AutoProduceRecordCopies ( uint32 records , char ** indexTable , char * dataTable )
{
uint32 recordsize = _loadInfo -> Meta -> GetRecordSize ();
uint32 offset = _header -> RecordCount * recordsize ;
uint32 idFieldOffset = _loadInfo -> Meta -> HasIndexFieldInData () ? _loadInfo -> Meta -> GetIndexFieldOffset () : 0 ;
for ( uint32 c = 0 ; c < GetRecordCopyCount (); ++ c )
{
DB2RecordCopy copy = GetRecordCopy ( c );
if ( copy . SourceRowId && copy . SourceRowId < records && copy . NewRowId < records && indexTable [ copy . SourceRowId ])
{
indexTable [ copy . NewRowId ] = & dataTable [ offset ];
memcpy ( indexTable [ copy . NewRowId ], indexTable [ copy . SourceRowId ], recordsize );
* (( uint32 * )( & dataTable [ offset + idFieldOffset ])) = copy . NewRowId ;
offset += recordsize ;
}
}
}
2017-03-08 18:10:02 +01:00
DB2Record DB2FileLoaderSparseImpl :: GetRecord ( uint32 recordNumber ) const
{
2018-02-18 16:32:03 +01:00
return DB2Record ( * this , recordNumber , _fieldAndArrayOffsets . get ());
2017-03-08 18:10:02 +01:00
}
2019-06-08 13:19:48 +02:00
DB2RecordCopy DB2FileLoaderSparseImpl :: GetRecordCopy ( uint32 copyNumber ) const
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
if ( copyNumber >= GetRecordCopyCount ())
return DB2RecordCopy {};
return _copyTable [ copyNumber ];
2017-03-08 18:10:02 +01:00
}
uint32 DB2FileLoaderSparseImpl :: GetRecordCount () const
{
2019-06-08 13:19:48 +02:00
return _catalog . size ();
2017-03-08 18:10:02 +01:00
}
uint32 DB2FileLoaderSparseImpl :: GetRecordCopyCount () const
{
2019-06-08 13:19:48 +02:00
return _copyTable . size ();
}
void DB2FileLoaderSparseImpl :: FillParentLookup ( char * dataTable )
{
int32 parentIdOffset = _loadInfo -> Meta -> GetParentIndexFieldOffset ();
uint32 recordSize = _loadInfo -> Meta -> GetRecordSize ();
2019-08-11 12:17:33 +02:00
uint32 recordIndexOffset = 0 ;
for ( uint32 i = 0 ; i < _header -> SectionCount ; ++ i )
2019-06-08 13:19:48 +02:00
{
2019-08-11 12:17:33 +02:00
DB2SectionHeader const & section = GetSection ( i );
2019-10-26 23:58:29 +02:00
if ( ! section . TactId )
2019-06-08 13:19:48 +02:00
{
2019-10-26 23:58:29 +02:00
for ( std :: size_t j = 0 ; j < _parentIndexes [ i ][ 0 ]. Entries . size (); ++ j )
2019-08-11 12:17:33 +02:00
{
2019-10-26 23:58:29 +02:00
uint32 parentId = _parentIndexes [ i ][ 0 ]. Entries [ j ]. ParentId ;
char * recordData = & dataTable [( _parentIndexes [ i ][ 0 ]. Entries [ j ]. RecordIndex + recordIndexOffset ) * recordSize ];
switch ( _loadInfo -> Meta -> Fields [ _loadInfo -> Meta -> ParentIndexField ]. Type )
{
case FT_SHORT :
2019-11-28 00:23:09 +01:00
{
if ( _loadInfo -> Meta -> ParentIndexField >= int32 ( _loadInfo -> Meta -> FileFieldCount ))
{
// extra field at the end
* reinterpret_cast < uint32 *> ( & recordData [ parentIdOffset ]) = parentId ;
}
else
{
// in data block, must fit
ASSERT ( parentId <= 0xFFFF , "ParentId value %u does not fit into uint16 field (%s in %s)" ,
parentId , _loadInfo -> Fields [ _loadInfo -> GetFieldIndexByMetaIndex ( _loadInfo -> Meta -> ParentIndexField )]. Name , _fileName );
* reinterpret_cast < uint16 *> ( & recordData [ parentIdOffset ]) = parentId ;
}
2019-10-26 23:58:29 +02:00
break ;
2019-11-28 00:23:09 +01:00
}
2019-10-26 23:58:29 +02:00
case FT_BYTE :
2019-11-28 00:23:09 +01:00
{
if ( _loadInfo -> Meta -> ParentIndexField >= int32 ( _loadInfo -> Meta -> FileFieldCount ))
{
// extra field at the end
* reinterpret_cast < uint32 *> ( & recordData [ parentIdOffset ]) = parentId ;
}
else
{
// in data block, must fit
ASSERT ( parentId <= 0xFF , "ParentId value %u does not fit into uint8 field (%s in %s)" ,
parentId , _loadInfo -> Fields [ _loadInfo -> GetFieldIndexByMetaIndex ( _loadInfo -> Meta -> ParentIndexField )]. Name , _fileName );
* reinterpret_cast < uint8 *> ( & recordData [ parentIdOffset ]) = parentId ;
}
2019-10-26 23:58:29 +02:00
break ;
2019-11-28 00:23:09 +01:00
}
2019-10-26 23:58:29 +02:00
case FT_INT :
* reinterpret_cast < uint32 *> ( & recordData [ parentIdOffset ]) = parentId ;
break ;
default :
ASSERT ( false , "Unhandled parent id type '%c' found in %s" , _loadInfo -> Meta -> Fields [ _loadInfo -> Meta -> ParentIndexField ]. Type , _fileName );
break ;
}
2019-08-11 12:17:33 +02:00
}
2019-06-08 13:19:48 +02:00
}
2019-08-11 12:17:33 +02:00
recordIndexOffset += section . RecordCount ;
2019-06-08 13:19:48 +02:00
}
}
uint32 DB2FileLoaderSparseImpl :: GetRecordSection ( uint32 recordNumber ) const
{
uint32 section = 0 ;
for (; section < _header -> SectionCount ; ++ section )
{
DB2SectionHeader const & sectionHeader = GetSection ( section );
if ( recordNumber < sectionHeader . CatalogDataCount )
break ;
recordNumber -= sectionHeader . CatalogDataCount ;
}
return section ;
2017-03-08 18:10:02 +01:00
}
2019-06-08 13:19:48 +02:00
unsigned char const * DB2FileLoaderSparseImpl :: GetRawRecordData ( uint32 recordNumber , uint32 const * section ) const
2017-03-08 18:10:02 +01:00
{
2019-06-08 13:19:48 +02:00
if ( recordNumber >= _catalog . size ())
return nullptr ;
if ( GetSection ( section ? * section : GetRecordSection ( recordNumber )). TactId )
return nullptr ;
_source -> SetPosition ( _catalog [ recordNumber ]. FileOffset );
uint8 * rawRecord = _recordBuffer . get ();
if ( ! _source -> Read ( rawRecord , _catalog [ recordNumber ]. RecordSize ))
2017-03-08 18:10:02 +01:00
return nullptr ;
CalculateAndStoreFieldOffsets ( rawRecord );
return rawRecord ;
}
2018-02-18 16:32:03 +01:00
uint32 DB2FileLoaderSparseImpl :: RecordGetId ( uint8 const * record , uint32 recordIndex ) const
2017-03-08 18:10:02 +01:00
{
if ( _loadInfo -> Meta -> HasIndexFieldInData ())
return RecordGetVarInt ( record , _loadInfo -> Meta -> GetIndexField (), 0 , false );
2019-06-08 13:19:48 +02:00
return _catalogIds [ recordIndex ];
2017-03-08 18:10:02 +01:00
}
2018-02-18 16:32:03 +01:00
uint8 DB2FileLoaderSparseImpl :: RecordGetUInt8 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const
2017-03-08 18:10:02 +01:00
{
ASSERT ( field < _header -> FieldCount );
return * reinterpret_cast < uint8 const *> ( record + GetFieldOffset ( field , arrayIndex ));
}
2018-02-18 16:32:03 +01:00
uint16 DB2FileLoaderSparseImpl :: RecordGetUInt16 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const
2017-03-08 18:10:02 +01:00
{
ASSERT ( field < _header -> FieldCount );
uint16 val = * reinterpret_cast < uint16 const *> ( record + GetFieldOffset ( field , arrayIndex ));
EndianConvert ( val );
return val ;
}
2018-02-18 16:32:03 +01:00
uint32 DB2FileLoaderSparseImpl :: RecordGetUInt32 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const
2017-03-08 18:10:02 +01:00
{
return RecordGetVarInt ( record , field , arrayIndex , false );
}
2018-02-18 16:32:03 +01:00
int32 DB2FileLoaderSparseImpl :: RecordGetInt32 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const
2017-03-08 18:10:02 +01:00
{
return int32 ( RecordGetVarInt ( record , field , arrayIndex , true ));
}
2018-02-18 16:32:03 +01:00
uint64 DB2FileLoaderSparseImpl :: RecordGetUInt64 ( uint8 const * record , uint32 field , uint32 arrayIndex ) const
{
ASSERT ( field < _header -> FieldCount );
uint64 val = * reinterpret_cast < uint64 const *> ( record + GetFieldOffset ( field , arrayIndex ));
EndianConvert ( val );
return val ;
}
float DB2FileLoaderSparseImpl :: RecordGetFloat ( uint8 const * record , uint32 field , uint32 arrayIndex ) const
2017-03-08 18:10:02 +01:00
{
ASSERT ( field < _header -> FieldCount );
float val = * reinterpret_cast < float const *> ( record + GetFieldOffset ( field , arrayIndex ));
EndianConvert ( val );
return val ;
}
2018-02-18 16:32:03 +01:00
char const * DB2FileLoaderSparseImpl :: RecordGetString ( uint8 const * record , uint32 field , uint32 arrayIndex ) const
2017-03-08 18:10:02 +01:00
{
ASSERT ( field < _header -> FieldCount );
return reinterpret_cast < char const *> ( record + GetFieldOffset ( field , arrayIndex ));
}
2018-02-18 16:32:03 +01:00
uint32 DB2FileLoaderSparseImpl :: RecordGetVarInt ( uint8 const * record , uint32 field , uint32 arrayIndex , bool isSigned ) const
2017-03-08 18:10:02 +01:00
{
ASSERT ( field < _header -> FieldCount );
2017-11-25 22:28:30 +01:00
uint32 val = 0 ;
memcpy ( & val , record + GetFieldOffset ( field , arrayIndex ), GetFieldSize ( field ));
2017-03-08 18:10:02 +01:00
EndianConvert ( val );
if ( isSigned )
2018-02-18 16:32:03 +01:00
return int32 ( val ) << _fields [ field ]. UnusedBits >> _fields [ field ]. UnusedBits ;
2017-03-08 18:10:02 +01:00
2018-02-18 16:32:03 +01:00
return val << _fields [ field ]. UnusedBits >> _fields [ field ]. UnusedBits ;
2017-03-08 18:10:02 +01:00
}
uint16 DB2FileLoaderSparseImpl :: GetFieldOffset ( uint32 field , uint32 arrayIndex ) const
{
2017-06-07 17:23:50 +02:00
return uint16 ( _fieldAndArrayOffsets [ _fieldAndArrayOffsets [ field ] + arrayIndex ]);
2017-03-08 18:10:02 +01:00
}
uint16 DB2FileLoaderSparseImpl :: GetFieldSize ( uint32 field ) const
{
ASSERT ( field < _header -> FieldCount );
2018-02-18 16:32:03 +01:00
return 4 - _fields [ field ]. UnusedBits / 8 ;
2017-03-08 18:10:02 +01:00
}
std :: size_t * DB2FileLoaderSparseImpl :: RecordCreateDetachedFieldOffsets ( std :: size_t * oldOffsets ) const
{
2018-02-18 16:32:03 +01:00
if ( oldOffsets != _fieldAndArrayOffsets . get ())
2017-03-08 18:10:02 +01:00
return oldOffsets ;
2017-06-07 17:23:50 +02:00
std :: size_t size = _loadInfo -> Meta -> FieldCount + _loadInfo -> FieldCount - ( ! _loadInfo -> Meta -> HasIndexFieldInData () ? 1 : 0 );
2017-03-08 18:10:02 +01:00
std :: size_t * newOffsets = new std :: size_t [ size ];
2018-02-18 16:32:03 +01:00
memcpy ( newOffsets , _fieldAndArrayOffsets . get (), size * sizeof ( std :: size_t ));
2017-03-08 18:10:02 +01:00
return newOffsets ;
}
void DB2FileLoaderSparseImpl :: RecordDestroyFieldOffsets ( std :: size_t *& fieldOffsets ) const
{
2018-02-18 16:32:03 +01:00
if ( fieldOffsets == _fieldAndArrayOffsets . get ())
2017-03-08 18:10:02 +01:00
return ;
delete [] fieldOffsets ;
fieldOffsets = nullptr ;
}
2018-02-18 16:32:03 +01:00
void DB2FileLoaderSparseImpl :: CalculateAndStoreFieldOffsets ( uint8 const * rawRecord ) const
2017-03-08 18:10:02 +01:00
{
std :: size_t offset = 0 ;
uint32 combinedField = _loadInfo -> Meta -> FieldCount ;
for ( uint32 field = 0 ; field < _loadInfo -> Meta -> FieldCount ; ++ field )
{
_fieldAndArrayOffsets [ field ] = combinedField ;
2018-03-16 18:44:57 +01:00
for ( uint32 arr = 0 ; arr < _loadInfo -> Meta -> Fields [ field ]. ArraySize ; ++ arr )
2017-03-08 18:10:02 +01:00
{
_fieldAndArrayOffsets [ combinedField ] = offset ;
2018-03-16 18:44:57 +01:00
switch ( _loadInfo -> Meta -> Fields [ field ]. Type )
2017-03-08 18:10:02 +01:00
{
case FT_BYTE :
case FT_SHORT :
case FT_INT :
2018-02-18 16:32:03 +01:00
case FT_LONG :
2017-03-08 18:10:02 +01:00
offset += GetFieldSize ( field );
break ;
case FT_FLOAT :
offset += sizeof ( float );
break ;
case FT_STRING :
2018-03-16 18:44:57 +01:00
case FT_STRING_NOT_LOCALIZED :
2017-03-08 18:10:02 +01:00
offset += strlen ( reinterpret_cast < char const *> ( rawRecord ) + offset ) + 1 ;
break ;
default :
2018-03-16 18:44:57 +01:00
ASSERT ( false , "Unknown format character '%c' found in %s meta" , _loadInfo -> Meta -> Fields [ field ]. Type , _fileName );
2017-03-08 18:10:02 +01:00
break ;
}
++ combinedField ;
}
}
}
uint32 DB2FileLoaderSparseImpl :: GetMaxId () const
{
return _header -> MaxId ;
}
2017-04-17 00:03:44 +02:00
DB2FileLoadInfo const * DB2FileLoaderSparseImpl :: GetLoadInfo () const
{
return _loadInfo ;
}
2020-05-10 15:29:47 +02:00
DB2SectionHeader & DB2FileLoaderSparseImpl :: GetSection ( uint32 section ) const
2018-03-16 18:44:57 +01:00
{
return _sections [ section ];
}
bool DB2FileLoaderSparseImpl :: IsSignedField ( uint32 field ) const
{
ASSERT ( field < _header -> FieldCount );
return _loadInfo -> Meta -> IsSignedField ( field );
}
2017-03-08 18:10:02 +01:00
DB2Record :: DB2Record ( DB2FileLoaderImpl const & db2 , uint32 recordIndex , std :: size_t * fieldOffsets )
2019-06-08 13:19:48 +02:00
: _db2 ( db2 ), _recordIndex ( recordIndex ), _recordData ( db2 . GetRawRecordData ( recordIndex , nullptr )), _fieldOffsets ( fieldOffsets )
2017-03-08 18:10:02 +01:00
{
}
DB2Record ::~ DB2Record ()
{
_db2 . RecordDestroyFieldOffsets ( _fieldOffsets );
}
DB2Record :: operator bool ()
{
return _recordData != nullptr ;
}
uint32 DB2Record :: GetId () const
{
return _db2 . RecordGetId ( _recordData , _recordIndex );
}
uint8 DB2Record :: GetUInt8 ( uint32 field , uint32 arrayIndex ) const
{
return _db2 . RecordGetUInt8 ( _recordData , field , arrayIndex );
}
2017-04-17 00:03:44 +02:00
uint8 DB2Record :: GetUInt8 ( char const * fieldName ) const
{
std :: pair < int32 , int32 > fieldIndex = _db2 . GetLoadInfo () -> GetFieldIndexByName ( fieldName );
ASSERT ( fieldIndex . first != - 1 , "Field with name %s does not exist!" , fieldName );
return _db2 . RecordGetUInt8 ( _recordData , uint32 ( fieldIndex . first ), uint32 ( fieldIndex . second ));
}
2017-03-08 18:10:02 +01:00
uint16 DB2Record :: GetUInt16 ( uint32 field , uint32 arrayIndex ) const
{
return _db2 . RecordGetUInt16 ( _recordData , field , arrayIndex );
}
2017-04-17 00:03:44 +02:00
uint16 DB2Record :: GetUInt16 ( char const * fieldName ) const
{
std :: pair < int32 , int32 > fieldIndex = _db2 . GetLoadInfo () -> GetFieldIndexByName ( fieldName );
ASSERT ( fieldIndex . first != - 1 , "Field with name %s does not exist!" , fieldName );
return _db2 . RecordGetUInt16 ( _recordData , uint32 ( fieldIndex . first ), uint32 ( fieldIndex . second ));
}
2017-03-08 18:10:02 +01:00
uint32 DB2Record :: GetUInt32 ( uint32 field , uint32 arrayIndex ) const
{
return _db2 . RecordGetUInt32 ( _recordData , field , arrayIndex );
}
2017-04-17 00:03:44 +02:00
uint32 DB2Record :: GetUInt32 ( char const * fieldName ) const
{
std :: pair < int32 , int32 > fieldIndex = _db2 . GetLoadInfo () -> GetFieldIndexByName ( fieldName );
ASSERT ( fieldIndex . first != - 1 , "Field with name %s does not exist!" , fieldName );
return _db2 . RecordGetUInt32 ( _recordData , uint32 ( fieldIndex . first ), uint32 ( fieldIndex . second ));
}
2017-03-08 18:10:02 +01:00
int32 DB2Record :: GetInt32 ( uint32 field , uint32 arrayIndex ) const
{
return _db2 . RecordGetInt32 ( _recordData , field , arrayIndex );
}
2017-04-17 00:03:44 +02:00
int32 DB2Record :: GetInt32 ( char const * fieldName ) const
{
std :: pair < int32 , int32 > fieldIndex = _db2 . GetLoadInfo () -> GetFieldIndexByName ( fieldName );
ASSERT ( fieldIndex . first != - 1 , "Field with name %s does not exist!" , fieldName );
return _db2 . RecordGetInt32 ( _recordData , uint32 ( fieldIndex . first ), uint32 ( fieldIndex . second ));
}
2018-02-18 16:32:03 +01:00
uint64 DB2Record :: GetUInt64 ( uint32 field , uint32 arrayIndex ) const
{
return _db2 . RecordGetUInt64 ( _recordData , field , arrayIndex );
}
uint64 DB2Record :: GetUInt64 ( char const * fieldName ) const
{
std :: pair < int32 , int32 > fieldIndex = _db2 . GetLoadInfo () -> GetFieldIndexByName ( fieldName );
ASSERT ( fieldIndex . first != - 1 , "Field with name %s does not exist!" , fieldName );
return _db2 . RecordGetUInt64 ( _recordData , uint32 ( fieldIndex . first ), uint32 ( fieldIndex . second ));
}
2017-03-08 18:10:02 +01:00
float DB2Record :: GetFloat ( uint32 field , uint32 arrayIndex ) const
{
return _db2 . RecordGetFloat ( _recordData , field , arrayIndex );
}
2017-04-17 00:03:44 +02:00
float DB2Record :: GetFloat ( char const * fieldName ) const
{
std :: pair < int32 , int32 > fieldIndex = _db2 . GetLoadInfo () -> GetFieldIndexByName ( fieldName );
ASSERT ( fieldIndex . first != - 1 , "Field with name %s does not exist!" , fieldName );
return _db2 . RecordGetFloat ( _recordData , uint32 ( fieldIndex . first ), uint32 ( fieldIndex . second ));
}
2017-03-08 18:10:02 +01:00
char const * DB2Record :: GetString ( uint32 field , uint32 arrayIndex ) const
{
return _db2 . RecordGetString ( _recordData , field , arrayIndex );
}
2017-04-17 00:03:44 +02:00
char const * DB2Record :: GetString ( char const * fieldName ) const
{
std :: pair < int32 , int32 > fieldIndex = _db2 . GetLoadInfo () -> GetFieldIndexByName ( fieldName );
ASSERT ( fieldIndex . first != - 1 , "Field with name %s does not exist!" , fieldName );
return _db2 . RecordGetString ( _recordData , uint32 ( fieldIndex . first ), uint32 ( fieldIndex . second ));
}
2017-03-08 18:10:02 +01:00
void DB2Record :: MakePersistent ()
{
_fieldOffsets = _db2 . RecordCreateDetachedFieldOffsets ( _fieldOffsets );
}
DB2FileLoader :: DB2FileLoader () : _impl ( nullptr )
{
}
DB2FileLoader ::~ DB2FileLoader ()
{
delete _impl ;
}
2019-06-08 13:19:48 +02:00
bool DB2FileLoader :: LoadHeaders ( DB2FileSource * source , DB2FileLoadInfo const * loadInfo )
2017-03-08 18:10:02 +01:00
{
if ( ! source -> IsOpen ())
return false ;
if ( ! source -> Read ( & _header , sizeof ( DB2Header )))
return false ;
EndianConvert ( _header . Signature );
EndianConvert ( _header . RecordCount );
EndianConvert ( _header . FieldCount );
EndianConvert ( _header . RecordSize );
EndianConvert ( _header . StringTableSize );
EndianConvert ( _header . TableHash );
EndianConvert ( _header . LayoutHash );
EndianConvert ( _header . MinId );
EndianConvert ( _header . MaxId );
EndianConvert ( _header . Locale );
EndianConvert ( _header . Flags );
EndianConvert ( _header . IndexField );
2017-04-06 23:39:34 +02:00
EndianConvert ( _header . TotalFieldCount );
2018-02-18 16:32:03 +01:00
EndianConvert ( _header . PackedDataOffset );
EndianConvert ( _header . ParentLookupCount );
EndianConvert ( _header . ColumnMetaSize );
2017-04-06 23:39:34 +02:00
EndianConvert ( _header . CommonDataSize );
2018-02-18 16:32:03 +01:00
EndianConvert ( _header . PalletDataSize );
2018-03-16 18:44:57 +01:00
EndianConvert ( _header . SectionCount );
2017-03-08 18:10:02 +01:00
2019-06-08 13:19:48 +02:00
if ( _header . Signature != 0x33434457 ) //'WDC3'
2017-03-08 18:10:02 +01:00
return false ;
2019-06-08 13:19:48 +02:00
if ( loadInfo && _header . LayoutHash != loadInfo -> Meta -> LayoutHash )
2017-03-08 18:10:02 +01:00
return false ;
2018-03-16 18:44:57 +01:00
if ( _header . ParentLookupCount > 1 )
return false ;
2019-06-08 13:19:48 +02:00
if ( loadInfo && ( _header . TotalFieldCount + ( loadInfo -> Meta -> ParentIndexField >= int32 ( _header . TotalFieldCount ) ? 1 : 0 ) != loadInfo -> Meta -> FieldCount ))
2018-03-16 18:44:57 +01:00
return false ;
2019-06-08 13:19:48 +02:00
if ( loadInfo && ( _header . ParentLookupCount && loadInfo -> Meta -> ParentIndexField == - 1 ))
2018-03-16 18:44:57 +01:00
return false ;
2020-06-23 08:54:12 +02:00
std :: unique_ptr < DB2SectionHeader [] > sections = std :: make_unique < DB2SectionHeader [] > ( _header . SectionCount );
2018-03-16 18:44:57 +01:00
if ( _header . SectionCount && ! source -> Read ( sections . get (), sizeof ( DB2SectionHeader ) * _header . SectionCount ))
return false ;
uint32 totalCopyTableSize = 0 ;
uint32 totalParentLookupDataSize = 0 ;
for ( uint32 i = 0 ; i < _header . SectionCount ; ++ i )
{
2019-06-08 13:19:48 +02:00
totalCopyTableSize += sections [ i ]. CopyTableCount * sizeof ( DB2RecordCopy );
2018-03-16 18:44:57 +01:00
totalParentLookupDataSize += sections [ i ]. ParentLookupDataSize ;
}
2019-06-08 13:19:48 +02:00
if ( loadInfo && ! ( _header . Flags & 0x1 ))
2018-02-18 16:32:03 +01:00
{
2019-08-10 19:03:24 +02:00
int64 expectedFileSize =
2018-02-18 16:32:03 +01:00
sizeof ( DB2Header ) +
2018-03-16 18:44:57 +01:00
sizeof ( DB2SectionHeader ) * _header . SectionCount +
2018-02-18 16:32:03 +01:00
sizeof ( DB2FieldEntry ) * _header . FieldCount +
_header . RecordCount * _header . RecordSize +
_header . StringTableSize +
2018-03-16 18:44:57 +01:00
( loadInfo -> Meta -> IndexField == - 1 ? _header . RecordCount * sizeof ( uint32 ) : 0 ) +
totalCopyTableSize +
2018-02-18 16:32:03 +01:00
_header . ColumnMetaSize +
_header . PalletDataSize +
_header . CommonDataSize +
2018-03-16 18:44:57 +01:00
totalParentLookupDataSize ;
2018-02-18 16:32:03 +01:00
if ( source -> GetFileSize () != expectedFileSize )
return false ;
}
2020-06-23 08:54:12 +02:00
std :: unique_ptr < DB2FieldEntry [] > fieldData = std :: make_unique < DB2FieldEntry [] > ( _header . FieldCount );
2018-02-18 16:32:03 +01:00
if ( ! source -> Read ( fieldData . get (), sizeof ( DB2FieldEntry ) * _header . FieldCount ))
return false ;
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 ;
if ( _header . ColumnMetaSize )
{
2020-06-23 08:54:12 +02:00
columnMeta = std :: make_unique < DB2ColumnMeta [] > ( _header . TotalFieldCount );
2018-02-18 16:32:03 +01:00
if ( ! source -> Read ( columnMeta . get (), _header . ColumnMetaSize ))
return false ;
2019-06-08 13:19:48 +02:00
if ( loadInfo )
{
ASSERT ( ! loadInfo -> Meta -> HasIndexFieldInData () ||
columnMeta [ loadInfo -> Meta -> IndexField ]. CompressionType == DB2ColumnCompression :: None ||
columnMeta [ loadInfo -> Meta -> IndexField ]. CompressionType == DB2ColumnCompression :: Immediate ||
columnMeta [ loadInfo -> Meta -> IndexField ]. CompressionType == DB2ColumnCompression :: SignedImmediate );
}
2018-02-18 16:32:03 +01:00
2020-06-23 08:54:12 +02:00
palletValues = std :: make_unique < std :: unique_ptr < DB2PalletValue [] > [] > ( _header . TotalFieldCount );
2018-02-18 16:32:03 +01:00
for ( uint32 i = 0 ; i < _header . TotalFieldCount ; ++ i )
{
if ( columnMeta [ i ]. CompressionType != DB2ColumnCompression :: Pallet )
continue ;
2020-06-23 08:54:12 +02:00
palletValues [ i ] = std :: make_unique < DB2PalletValue [] > ( columnMeta [ i ]. AdditionalDataSize / sizeof ( DB2PalletValue ));
2018-02-18 16:32:03 +01:00
if ( ! source -> Read ( palletValues [ i ]. get (), columnMeta [ i ]. AdditionalDataSize ))
return false ;
}
2020-06-23 08:54:12 +02:00
palletArrayValues = std :: make_unique < std :: unique_ptr < DB2PalletValue [] > [] > ( _header . TotalFieldCount );
2018-02-18 16:32:03 +01:00
for ( uint32 i = 0 ; i < _header . TotalFieldCount ; ++ i )
{
if ( columnMeta [ i ]. CompressionType != DB2ColumnCompression :: PalletArray )
continue ;
2020-06-23 08:54:12 +02:00
palletArrayValues [ i ] = std :: make_unique < DB2PalletValue [] > ( columnMeta [ i ]. AdditionalDataSize / sizeof ( DB2PalletValue ));
2018-02-18 16:32:03 +01:00
if ( ! source -> Read ( palletArrayValues [ i ]. get (), columnMeta [ i ]. AdditionalDataSize ))
return false ;
}
2020-06-23 08:54:12 +02:00
std :: unique_ptr < std :: unique_ptr < DB2CommonValue [] > [] > commonData = std :: make_unique < std :: unique_ptr < DB2CommonValue [] > [] > ( _header . TotalFieldCount );
commonValues = std :: make_unique < std :: unordered_map < uint32 , uint32 > [] > ( _header . TotalFieldCount );
2018-02-18 16:32:03 +01:00
for ( uint32 i = 0 ; i < _header . TotalFieldCount ; ++ i )
{
if ( columnMeta [ i ]. CompressionType != DB2ColumnCompression :: CommonData )
continue ;
if ( ! columnMeta [ i ]. AdditionalDataSize )
continue ;
2020-06-23 08:54:12 +02:00
commonData [ i ] = std :: make_unique < DB2CommonValue [] > ( columnMeta [ i ]. AdditionalDataSize / sizeof ( DB2CommonValue ));
2018-02-18 16:32:03 +01:00
if ( ! source -> Read ( commonData [ i ]. get (), columnMeta [ i ]. AdditionalDataSize ))
return false ;
2017-03-08 18:10:02 +01:00
2018-02-18 16:32:03 +01:00
uint32 numExtraValuesForField = columnMeta [ i ]. AdditionalDataSize / sizeof ( DB2CommonValue );
for ( uint32 record = 0 ; record < numExtraValuesForField ; ++ record )
{
uint32 recordId = commonData [ i ][ record ]. RecordId ;
uint32 value = commonData [ i ][ record ]. Value ;
EndianConvert ( value );
commonValues [ i ][ recordId ] = value ;
}
}
}
2018-03-16 18:44:57 +01:00
if ( ! ( _header . Flags & 0x1 ))
_impl = new DB2FileLoaderRegularImpl ( source -> GetFileName (), loadInfo , & _header );
else
2019-06-08 13:19:48 +02:00
_impl = new DB2FileLoaderSparseImpl ( source -> GetFileName (), loadInfo , & _header , source );
2018-03-16 18:44:57 +01:00
_impl -> LoadColumnData ( std :: move ( sections ), std :: move ( fieldData ), std :: move ( columnMeta ), std :: move ( palletValues ), std :: move ( palletArrayValues ), std :: move ( commonValues ));
2019-06-08 13:19:48 +02:00
return true ;
}
bool DB2FileLoader :: Load ( DB2FileSource * source , DB2FileLoadInfo const * loadInfo )
{
if ( ! LoadHeaders ( source , loadInfo ))
return false ;
2018-03-16 18:44:57 +01:00
std :: vector < uint32 > idTable ;
std :: vector < DB2RecordCopy > copyTable ;
2019-08-11 12:17:33 +02:00
std :: vector < std :: vector < DB2IndexData >> parentIndexes ;
2019-06-08 13:19:48 +02:00
if ( loadInfo && ! loadInfo -> Meta -> HasIndexFieldInData () && _header . RecordCount )
2018-03-16 18:44:57 +01:00
idTable . reserve ( _header . RecordCount );
2019-10-26 23:58:29 +02:00
if ( _header . ParentLookupCount )
{
parentIndexes . resize ( _header . SectionCount );
for ( std :: vector < DB2IndexData >& parentIndexesForSection : parentIndexes )
parentIndexesForSection . resize ( _header . ParentLookupCount );
}
2018-03-16 18:44:57 +01:00
for ( uint32 i = 0 ; i < _header . SectionCount ; ++ i )
2018-02-18 16:32:03 +01:00
{
2020-05-10 15:29:47 +02:00
DB2SectionHeader & section = _impl -> GetSection ( i );
2018-03-16 18:44:57 +01:00
2019-06-08 13:19:48 +02:00
if ( section . TactId )
{
2020-05-10 15:29:47 +02:00
switch ( source -> HandleEncryptedSection ( section ))
{
case DB2EncryptedSectionHandling :: Skip :
_impl -> SkipEncryptedSection ( i );
idTable . resize ( idTable . size () + section . IdTableSize / sizeof ( uint32 ));
continue ;
case DB2EncryptedSectionHandling :: Process :
section . TactId = 0 ;
break ;
default :
break ;
}
2019-06-08 13:19:48 +02:00
}
2018-09-11 21:48:16 +02:00
if ( ! source -> SetPosition ( section . FileOffset ))
return false ;
2018-03-16 18:44:57 +01:00
if ( ! _impl -> LoadTableData ( source , i ))
return false ;
if ( ! _impl -> LoadCatalogData ( source , i ))
return false ;
2019-06-08 13:19:48 +02:00
if ( loadInfo )
{
ASSERT ( ! loadInfo -> Meta -> HasIndexFieldInData () || section . IdTableSize == 0 );
ASSERT ( loadInfo -> Meta -> HasIndexFieldInData () || section . IdTableSize == 4 * section . RecordCount );
}
2018-03-16 18:44:57 +01:00
2019-06-08 13:19:48 +02:00
if ( section . IdTableSize )
2018-02-18 16:32:03 +01:00
{
2018-03-16 18:44:57 +01:00
std :: size_t idTableSize = idTable . size ();
2019-06-08 13:19:48 +02:00
idTable . resize ( idTableSize + section . IdTableSize / sizeof ( uint32 ));
2018-03-16 18:44:57 +01:00
if ( ! source -> Read ( & idTable [ idTableSize ], section . IdTableSize ))
2018-02-18 16:32:03 +01:00
return false ;
2018-03-16 18:44:57 +01:00
}
2018-02-18 16:32:03 +01:00
2019-06-08 13:19:48 +02:00
if ( ! ( _header . Flags & 0x1 ) && section . CopyTableCount )
2018-03-16 18:44:57 +01:00
{
std :: size_t copyTableSize = copyTable . size ();
2019-06-08 13:19:48 +02:00
copyTable . resize ( copyTableSize + section . CopyTableCount );
if ( ! source -> Read ( & copyTable [ copyTableSize ], section . CopyTableCount * sizeof ( DB2RecordCopy )))
2018-02-18 16:32:03 +01:00
return false ;
}
2018-03-16 18:44:57 +01:00
if ( _header . ParentLookupCount )
{
2019-10-26 23:58:29 +02:00
std :: vector < DB2IndexData >& parentIndexesForSection = parentIndexes [ i ];
2019-08-11 12:17:33 +02:00
for ( uint32 j = 0 ; j < _header . ParentLookupCount ; ++ j )
2018-03-16 18:44:57 +01:00
{
2019-06-08 13:19:48 +02:00
DB2IndexDataInfo indexInfo ;
if ( ! source -> Read ( & indexInfo , sizeof ( DB2IndexDataInfo )))
2018-03-16 18:44:57 +01:00
return false ;
2019-06-08 13:19:48 +02:00
if ( ! indexInfo . NumEntries )
2018-03-16 18:44:57 +01:00
continue ;
2019-08-11 12:17:33 +02:00
parentIndexesForSection [ j ]. Entries . resize ( indexInfo . NumEntries );
if ( ! source -> Read ( parentIndexesForSection [ j ]. Entries . data (), sizeof ( DB2IndexEntry ) * indexInfo . NumEntries ))
2018-03-16 18:44:57 +01:00
return false ;
}
}
2018-02-18 16:32:03 +01:00
}
2018-03-16 18:44:57 +01:00
_impl -> SetAdditionalData ( std :: move ( idTable ), std :: move ( copyTable ), std :: move ( parentIndexes ));
2019-06-08 13:19:48 +02:00
if ( loadInfo )
2018-03-16 18:44:57 +01:00
{
2019-06-08 13:19:48 +02:00
uint32 fieldIndex = 0 ;
if ( ! loadInfo -> Meta -> HasIndexFieldInData ())
{
2019-11-28 00:23:09 +01:00
ASSERT ( ! loadInfo -> Fields [ 0 ]. IsSigned , "ID must be unsigned in %s" , source -> GetFileName ());
2019-06-08 13:19:48 +02:00
++ fieldIndex ;
}
for ( uint32 f = 0 ; f < loadInfo -> Meta -> FieldCount ; ++ f )
{
2019-11-28 00:23:09 +01:00
ASSERT ( loadInfo -> Fields [ fieldIndex ]. IsSigned == _impl -> IsSignedField ( f ), "Mismatched field signedness for field %u (%s) in %s" , f , loadInfo -> Fields [ fieldIndex ]. Name , source -> GetFileName ());
2019-06-08 13:19:48 +02:00
fieldIndex += loadInfo -> Meta -> Fields [ f ]. ArraySize ;
}
2018-03-16 18:44:57 +01:00
}
2018-02-18 16:32:03 +01:00
return true ;
2017-03-08 18:10:02 +01:00
}
char * DB2FileLoader :: AutoProduceData ( uint32 & count , char **& indexTable , std :: vector < char *>& stringPool )
{
return _impl -> AutoProduceData ( count , indexTable , stringPool );
}
2018-05-12 16:24:41 +02:00
char * DB2FileLoader :: AutoProduceStrings ( char ** indexTable , uint32 indexTableSize , uint32 locale )
2017-03-08 18:10:02 +01:00
{
2018-05-12 16:24:41 +02:00
return _impl -> AutoProduceStrings ( indexTable , indexTableSize , locale );
2017-03-08 18:10:02 +01:00
}
void DB2FileLoader :: AutoProduceRecordCopies ( uint32 records , char ** indexTable , char * dataTable )
{
_impl -> AutoProduceRecordCopies ( records , indexTable , dataTable );
}
uint32 DB2FileLoader :: GetRecordCount () const
{
return _impl -> GetRecordCount ();
}
uint32 DB2FileLoader :: GetRecordCopyCount () const
{
return _impl -> GetRecordCopyCount ();
}
uint32 DB2FileLoader :: GetMaxId () const
{
return _impl -> GetMaxId ();
}
2019-06-08 13:19:48 +02:00
DB2SectionHeader const & DB2FileLoader :: GetSectionHeader ( uint32 section ) const
{
return _impl -> GetSection ( section );
}
2017-03-08 18:10:02 +01:00
DB2Record DB2FileLoader :: GetRecord ( uint32 recordNumber ) const
{
return _impl -> GetRecord ( recordNumber );
}
DB2RecordCopy DB2FileLoader :: GetRecordCopy ( uint32 copyNumber ) const
{
return _impl -> GetRecordCopy ( copyNumber );
}