#include "../../include/rdu/RDUReader.h" #include "../../include/rdu/RDUFileHeader.h" namespace { template< typename Length_T > bool ReadStringData( KStream* pStream, std::string* pString ) { Length_T nLength = 0; if( pStream->Read( &nLength, sizeof( nLength ) ) != sizeof( nLength ) ) { return false; } if( nLength > 0 ) { char* pStringData = new char[nLength+1]; if( pStream->Read( pStringData, nLength ) != nLength ) { delete [] pStringData; return false; } pStringData[nLength] = '\0'; *pString = pStringData; delete [] pStringData; } return true; } }; RDUReader::RDUReader() : m_bIsMyStream( false ) , m_pRDUFile( NULL ) , m_nCurrentRowPos( 0 ) , m_nTotalRowCount( 0 ) { } RDUReader::~RDUReader() { Close(); } bool RDUReader::Open( const std::string& file_name ) { FILE* fp = NULL; fopen_s( &fp, file_name.c_str(), "rb" ); if( fp == NULL ) { return false; } m_pRDUFile = new KRealFile( fp ); m_bIsMyStream = true; if( ReadHeader() == false ) { return false; } return true; } bool RDUReader::Open( KStream* pStream ) { m_pRDUFile = pStream; m_bIsMyStream = false; if( ReadHeader() == false ) { return false; } return true; } bool RDUReader::ReadHeader() { if( CheckHeader() == false ) { return false; } if( ReadColumnInfo() == false ) { return false; } if( ReadIndexInfo() == false ) { return false; } if( ReadDataHeader() == false ) { return false; } return true; } void RDUReader::Close() { if( m_pRDUFile != NULL ) { if( m_bIsMyStream == true ) { delete m_pRDUFile; } m_pRDUFile = NULL; m_bIsMyStream = false; } { std::vector< COLUMN_SCHEMA* >::const_iterator pos = m_vColumnSchema.begin(); std::vector< COLUMN_SCHEMA* >::const_iterator end = m_vColumnSchema.end(); for( ; pos != end; ++pos ) { const COLUMN_SCHEMA* pSchema = (*pos); if( pSchema != NULL ) { delete pSchema; } } m_vColumnSchema.clear(); } { std::vector< INDEX_SCHEMA* >::const_iterator pos = m_vIndexSchema.begin(); std::vector< INDEX_SCHEMA* >::const_iterator end = m_vIndexSchema.end(); for( ; pos != end; ++pos ) { const INDEX_SCHEMA* pSchema = (*pos); if( pSchema != NULL ) { delete pSchema; } } m_vIndexSchema.clear(); } m_nCurrentRowPos = 0; m_nTotalRowCount = 0; } const std::vector< COLUMN_SCHEMA* >& RDUReader::GetColumnSchema() const { return m_vColumnSchema; } const std::vector< INDEX_SCHEMA* >& RDUReader::GetIndexSchema() const { return m_vIndexSchema; } int RDUReader::GetRowCount() const { return m_nTotalRowCount; } bool RDUReader::CheckHeader() { RDU_FILE_HEADER RDUFileHeader; if( m_pRDUFile->Read( &RDUFileHeader, sizeof( RDUFileHeader ) ) != sizeof( RDUFileHeader ) ) { return false; } if( ::strncmp( RDUFileHeader.szFileTag, RDUFILE_HEADER_TAG, RDU_FILE_HEADER::FILE_TAG_LENGTH ) ) { return false; } if( RDUFileHeader.nMajorVersion != RDUFILE_MAJOR_VERSION || RDUFileHeader.nMinorVersion != RDUFILE_MINOR_VERSION ) { return false; } return true; } bool RDUReader::ReadColumnInfo() { unsigned short nColumnCount = 0; if( m_pRDUFile->Read( &nColumnCount, sizeof( nColumnCount ) ) != sizeof( nColumnCount ) ) { return false; } for( int nColumnIndex = 0; nColumnIndex < nColumnCount; ++nColumnIndex ) { COLUMN_SCHEMA* pCS = new COLUMN_SCHEMA; if( ReadColumnSchema( pCS ) == false ) { delete pCS; return false; } m_vColumnSchema.push_back( pCS ); } return true; } bool RDUReader::ReadColumnSchema( COLUMN_SCHEMA* pCS ) { if( ReadStringData< unsigned char >( m_pRDUFile, &pCS->strName ) == false ) { return false; } DWORD nReadBytes = 0; StatusFlagRawDataType nColumnStatusFlag; if( m_pRDUFile->Read( &pCS->eXUserType, sizeof( pCS->eXUserType ) ) != sizeof( pCS->eXUserType ) || m_pRDUFile->Read( &pCS->nLength, sizeof( pCS->nLength ) ) != sizeof( pCS->nLength ) || m_pRDUFile->Read( &pCS->nXPrec, sizeof( pCS->nXPrec ) ) != sizeof( pCS->nXPrec ) || m_pRDUFile->Read( &pCS->nXScale, sizeof( pCS->nXScale ) ) != sizeof( pCS->nXScale ) || m_pRDUFile->Read( &nColumnStatusFlag, sizeof( nColumnStatusFlag ) ) != sizeof( nColumnStatusFlag ) ) { return false; } pCS->StatusFlag.SetRawData( nColumnStatusFlag ); if( ReadStringData< unsigned char >( m_pRDUFile, &pCS->strDefaultValue ) == false ) { return false; } if( ReadStringData< unsigned char >( m_pRDUFile, &pCS->strCollation ) == false ) { return false; } return true; } bool RDUReader::ReadIndexInfo() { unsigned short nIndexCount = 0; if( m_pRDUFile->Read( &nIndexCount, sizeof( nIndexCount ) ) != sizeof( nIndexCount ) ) { return false; } for( int nIndex = 0; nIndex < nIndexCount; ++nIndex ) { INDEX_SCHEMA* pIS = new INDEX_SCHEMA; if( ReadIndexSchema( pIS ) == false ) { delete pIS; return false; } m_vIndexSchema.push_back( pIS ); } return true; } bool RDUReader::ReadIndexSchema( INDEX_SCHEMA* pIS ) { StatusFlagRawDataType nStatusFlagRawDataBuffer; if( m_pRDUFile->Read( &pIS->nID, sizeof( pIS->nID ) ) != sizeof( pIS->nID ) || m_pRDUFile->Read( &pIS->eType, sizeof( pIS->eType ) ) != sizeof( pIS->eType ) || m_pRDUFile->Read( &nStatusFlagRawDataBuffer, sizeof( nStatusFlagRawDataBuffer ) ) != sizeof( nStatusFlagRawDataBuffer ) ) { return false; } pIS->StatusFlag.SetRawData( nStatusFlagRawDataBuffer ); if( ReadStringData< unsigned char >( m_pRDUFile, &pIS->strName ) == false ) { return false; } unsigned short nColumnCount = 0; if( m_pRDUFile->Read( &nColumnCount, sizeof( nColumnCount ) ) != sizeof( nColumnCount ) ) { return false; } for( int nColumnIndex = 0; nColumnIndex < nColumnCount; ++nColumnIndex ) { INDEX_SCHEMA::COLUMN_INFO* pCI = new INDEX_SCHEMA::COLUMN_INFO; if( ReadStringData< unsigned char >( m_pRDUFile, &pCI->strName ) == false ) { delete pCI; return false; } if( m_pRDUFile->Read( &nStatusFlagRawDataBuffer, sizeof( nStatusFlagRawDataBuffer ) ) != sizeof( nStatusFlagRawDataBuffer ) ) { delete pCI; return false; } pCI->StatusFlag.SetRawData( nStatusFlagRawDataBuffer ); pIS->vColumnInfo.push_back( pCI ); } return true; } bool RDUReader::ReadDataHeader() { if( m_pRDUFile->Read( &m_nTotalRowCount, sizeof( m_nTotalRowCount ) ) != sizeof( m_nTotalRowCount ) ) { return false; } m_nCurrentRowPos = 0; return true; } bool RDUReader::Fetch( RDURow* pRow ) { if( m_nCurrentRowPos >= m_nTotalRowCount ) { return false; } if( ReadRow( pRow ) == false ) { pRow->Clear(); return false; } ++m_nCurrentRowPos; return true; } bool RDUReader::ReadRow( RDURow* pRow ) { if( pRow->vDatas.size() != m_vColumnSchema.size() ) { pRow->Clear(); } std::vector< COLUMN_SCHEMA* >::const_iterator pos = m_vColumnSchema.begin(); std::vector< COLUMN_SCHEMA* >::const_iterator end = m_vColumnSchema.end(); for( int nIndex = 0; pos != end; ++pos, ++nIndex ) { COLUMN_SCHEMA* pColumn = (*pos); ColumnData* pCD = pRow->At( nIndex ); if( pCD == NULL ) { pCD = new ColumnData; pRow->vDatas.push_back( pCD ); } pCD->pSchema = pColumn; if( ReadColumnData( pCD ) == false ) { return false; } } return true; } bool RDUReader::ReadColumnData( ColumnData* pCD ) { // NULL 허용인 컬럼의 경우 NULL 값 여부를 나타내는 1바이트 확인 if( pCD->pSchema->IsNullable() == true ) { bool bIsNull = false; if( m_pRDUFile->Read( &bIsNull, sizeof( bIsNull ) ) != sizeof( bIsNull ) ) { return false; } pCD->bIsNull = bIsNull; } if( pCD->bIsNull == false ) { pCD->nDataSize = pCD->pSchema->nLength; unsigned short nBytesToAlloc = pCD->nDataSize; switch( pCD->pSchema->eXUserType ) { case COLUMN_SCHEMA::USERTYPE_VARCHAR: case COLUMN_SCHEMA::USERTYPE_CHAR: case COLUMN_SCHEMA::USERTYPE_NVARCHAR: case COLUMN_SCHEMA::USERTYPE_NCHAR: { if( m_pRDUFile->Read( &pCD->nDataSize, sizeof( pCD->nDataSize ) ) != sizeof( pCD->nDataSize ) ) { return false; } nBytesToAlloc = pCD->nDataSize; nBytesToAlloc += sizeof( char ); // NULL 추가를 위해 if( pCD->pSchema->eXUserType == COLUMN_SCHEMA::USERTYPE_NVARCHAR || pCD->pSchema->eXUserType == COLUMN_SCHEMA::USERTYPE_NCHAR ) { nBytesToAlloc += (sizeof( wchar_t ) - sizeof( char )); // 유니코드 } } break; } assert( nBytesToAlloc >= pCD->nDataSize ); if( nBytesToAlloc < pCD->nDataSize ) { return false; } if( pCD->pData == NULL || pCD->nAllocSize < nBytesToAlloc ) { pCD->pData = new char[nBytesToAlloc]; pCD->nAllocSize = nBytesToAlloc; } if( m_pRDUFile->Read( pCD->pData, pCD->nDataSize ) != pCD->nDataSize ) { return false; } if( pCD->pSchema->eXUserType == COLUMN_SCHEMA::USERTYPE_VARCHAR || pCD->pSchema->eXUserType == COLUMN_SCHEMA::USERTYPE_CHAR ) { pCD->pData[pCD->nDataSize] = '\0'; } else if( pCD->pSchema->eXUserType == COLUMN_SCHEMA::USERTYPE_NVARCHAR || pCD->pSchema->eXUserType == COLUMN_SCHEMA::USERTYPE_NCHAR ) { wchar_t* pWData = reinterpret_cast< wchar_t* >( pCD->pData ); pWData[pCD->nDataSize/sizeof( wchar_t )] = L'\0'; } } return true; }