switch(sColumnType)
            {
                case SMI_COLUMN_TYPE_LOB:
                    IDE_ASSERT( sFile.read( sOffset, &sSize, ID_SIZEOF(UInt))
                                == IDE_SUCCESS);
                    sOffset += ID_SIZEOF(UInt);

                    idlOS::printf(" LOB:%"ID_UINT32_FMT"", sSize);
                    sOffset += sSize;

                    break;

                default:
                    break;
            }

/**
 *
 */

#include <idl.h>
#include <ide.h>
#include <idu.h>
#include <smErrorCode.h>
#include <smDef.h>
#include <svm.h>
#include <svcDef.h>
#include <svcRecord.h>
#include <smcTable.h>
#include <smi.h>
#include <smiVolTableBackup.h>
#include <smxTrans.h>
#include <svcLob.h>

/* PROJ-2174 Supporting LOB in the volatile tablespace */
#define SMI_MAX_LOB_BACKUP_BUFFER_SIZE (1024*1024)

/***********************************************************************
 * Description : aTable에 대해 Backup 또는 Restore를 준비한다.
 *
 * aTable    - [IN] File에 대한 Table Header
 ***********************************************************************/
IDE_RC smiVolTableBackup::initialize(const void* aTable, SChar * aBackupFileName)
{
    SChar sFileName[SM_MAX_FILE_NAME];

    IDE_DASSERT(aTable != NULL);

    mTableHeader = (smcTableHeader*)((UChar*)aTable + SMP_SLOT_HEADER_SIZE);

    idlOS::snprintf(sFileName,
                    SM_MAX_FILE_NAME,
                    "%s%"ID_vULONG_FMT"%s",
                    smcTable::getBackupDir(), smcTable::getTableOID(mTableHeader),
                    SM_TABLE_BACKUP_EXT);

    IDE_TEST(mFile.initialize(sFileName)
             != IDE_SUCCESS);

    /* BUG-34262
     * When alter table add/modify/drop column, backup file cannot be
     * deleted.
     */
    if( aBackupFileName != NULL )
    {
        idlOS::strncpy( aBackupFileName, sFileName, SM_MAX_FILE_NAME );
    }

    mBuffer       = NULL;
    mOffset       = 0;
    mBufferSize   = 0;
    mArrColumn    = NULL;

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    return IDE_FAILURE;
}

/***********************************************************************
 * Description : 할당된 자원을 반납한다.
 *
 ***********************************************************************/
IDE_RC smiVolTableBackup::destroy()
{
    IDE_ASSERT(mBuffer == NULL);
    IDE_TEST(mFile.destroy() != IDE_SUCCESS);

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    return IDE_FAILURE;
}

/* PROJ-2174 Supporting LOB in the volatile tablespace */
/***********************************************************************
 * Description : aTableOID에 해당하는 Table을 디스크로 내린다.
 *               Filename은 다음과 같이 된다.
 *                - Filename: smcTable::getBackupDir()/smcTable::getTableOID(aTable)
 *                - EXT: SM_TABLE_BACKUP_EXT
 *
 *               File Format
 *                - File Header(smcBackupFileHeader)
 *                - Column List
 *                  Column Cnt (UInt)
 *                  column1 .. column n (smiColumn)
 *                - Data
 *                   row들(column1, column2, column3)
 *                    - LOB Column은 파일에 기록시 뒤 몰아서 기록한다.
 *                      ex) c1: int, c2: lob, c3: lob, c4:string
 *                          c1, c4, c2, c3순으로 백업파일에 기록.
 *
 *                    - Fixed: Data
 *                    - LOB, VAR: Length(UInt), Data
 *
 *                - File Tail(smcBackupFileTail)
 *
 * aStatement    - [IN] Statement
 * aTable        - [IN] Table Header
 * aStatistics   - [IN] 통계정보
 ***********************************************************************/
IDE_RC smiVolTableBackup::backup(smiStatement   * aStatement,
                                 const void     * aTable,
                                 idvSQL         * aStatistics)
{
    smiTableCursor      sCursor;
    UInt                sState      = 0;
    UInt                sCheckCount;
    SChar             * sCurRow;
    smiCursorProperties sCursorProperties;
    smxTrans          * sTrans;
    /* BUG-34262 [SM] When alter table add/modify/drop column, backup file
     * cannot be deleted.
     * table을 backup하고 mTableHeader->mNullOID를 SM_NULL_OID변경하고 예외
     * 발생시 이전 OID로 복원해야 합니다. 하지만 남는 로그가 redo only여서
     * undo되지않아 mTableHeader->mNullOID이 엉뚱한 값이들어있는 상태가 됩니다.
     * 코드를 삭제하는 대신에 주석처리 합니다.
    scPageID            sCatPageID;
    */
    scGRID              sRowGRID;
    UInt                sRowSize;
    UInt                sRowMaxSize = 0;
    SChar             * sNullRowPtr;
    smiColumn        ** sLobColumnList;
    UInt                sLobColumnCnt;

    // To fix BUG-14818
    sCursor.initialize();

    SMI_CURSOR_PROP_INIT( &sCursorProperties, aStatistics, NULL );
    sCursorProperties.mLockWaitMicroSec = 0;
    sCursorProperties.mIsUndoLogging    = ID_FALSE;

    sTrans = (smxTrans*)aStatement->mTrans->getTrans();
    /* BUG-34262 [SM] When alter table add/modify/drop column, backup file
     * cannot be deleted.
     * table을 backup하고 mTableHeader->mNullOID를 SM_NULL_OID변경하고 예외
     * 발생시 이전 OID로 복원해야 합니다. 하지만 남는 로그가 redo only여서
     * undo되지않아 mTableHeader->mNullOID이 엉뚱한 값이들어있는 상태가 됩니다.
     * 코드를 삭제하는 대신에 주석처리 합니다.

    sCatPageID = SM_MAKE_PID( mTableHeader->mSelfOID );
     */

    sState  = 1;    /* 백업 파일 준비 */

    IDE_TEST_RAISE( smcTable::waitForFileDelete( sTrans->mStatistics,
                                                 mFile.getFileName() )
                    != IDE_SUCCESS,
                    err_wait_for_file_delete );

    /* create backup file and write backup file header */
    IDE_TEST( prepareAccessFile(ID_TRUE/*Write*/) != IDE_SUCCESS );

    sState = 2;     /* Lob Column List 생성 */

    /* PROJ-2174 Supporting LOB in the volatile tablespace */
    IDE_TEST( smcTable::makeLobColumnList( mTableHeader,
                                           &sLobColumnList,
                                           &sLobColumnCnt )
              != IDE_SUCCESS );

    sState = 3;     /* 백업 파일 header 및 컬럼 정보 쓰기, 커서 open */

    IDE_TEST( appendBackupFileHeader() != IDE_SUCCESS );

    // Table의 smiColumn List정보를 파일에 기록한다.
    IDE_TEST( appendTableColumnInfo() != IDE_SUCCESS );

    // key filer등 기타 pointer등을 default로 구해서 setting해야 한다.
    IDE_TEST(sCursor.open( aStatement,
                           aTable,
                           NULL,
                           smiGetRowSCN(aTable),
                           NULL,
                           smiGetDefaultKeyRange(),
                           smiGetDefaultKeyRange(),
                           smiGetDefaultFilter(),
                           SMI_LOCK_READ|SMI_TRAVERSE_FORWARD|SMI_PREVIOUS_DISABLE,
                           SMI_SELECT_CURSOR,
                           &sCursorProperties )
             != IDE_SUCCESS);

    sState = 4;     /* 실제 data 백업 */

    /* 정상적인 table이면 mNullOID는 반드시 존재해야 한다. */
    IDE_ASSERT( mTableHeader->mNullOID != SM_NULL_OID );

    IDE_ASSERT( smmManager::getOIDPtr( mTableHeader->mSpaceID,
                                       mTableHeader->mNullOID,
                                       (void**)&sNullRowPtr )
                == IDE_SUCCESS );

    // Append NULL Row
    /* PROJ-2174 Supporting LOB in the volatile tablespce */
    IDE_TEST( appendRow( &sCursor,
                         sLobColumnList,
                         sLobColumnCnt,
                         sNullRowPtr,
                         &sRowSize )
             != IDE_SUCCESS );

    if( sRowSize > sRowMaxSize )
    {
        sRowMaxSize = sRowSize;
    }

    IDE_TEST( sCursor.beforeFirst() != IDE_SUCCESS );

    IDE_TEST( sCursor.readRow ((const void**)&sCurRow,
                               &sRowGRID,
                               SMI_FIND_NEXT )
              != IDE_SUCCESS );

    sCheckCount = 0;
    while( sCurRow != NULL )
    {
        IDE_ASSERT( sNullRowPtr != sCurRow );

        /* PROJ-2174 Supporting LOB in the volatile tablespace */
        IDE_TEST( appendRow( &sCursor,
                             sLobColumnList,
                             sLobColumnCnt,
                             sCurRow,
                             &sRowSize ) != IDE_SUCCESS );

        if( sRowSize > sRowMaxSize )
        {
            sRowMaxSize = sRowSize;
        }

        IDE_TEST( sCursor.readRow( (const void**)&sCurRow,
                                   &sRowGRID,
                                   SMI_FIND_NEXT )
                 != IDE_SUCCESS);

        sCheckCount++;

        if( sCheckCount == 100 )
        {
            IDE_TEST( iduCheckSessionEvent( sTrans->mStatistics )
                     != IDE_SUCCESS );
            sCheckCount = 0;
        }
    }

    sState = 3;     /* 커서 close, 백업 파일 tail 쓰기 */

    IDE_TEST( sCursor.close() != IDE_SUCCESS );

    IDE_TEST( appendBackupFileTail( mTableHeader->mSelfOID,
                                    mOffset + ID_SIZEOF( smcBackupFileTail ),
                                    sRowMaxSize ) != IDE_SUCCESS );

    sState = 2;     /* Lob Column List 파괴 */

    IDE_TEST( smcTable::destLobColumnList( sLobColumnList )
             != IDE_SUCCESS );

    sState = 1;     /* 백업 파일 Close */

    IDE_TEST( finishAccessFile() != IDE_SUCCESS );

    /* BUG-34262 [SM] When alter table add/modify/drop column, backup file
     * cannot be deleted.
     * table을 backup하고 mTableHeader->mNullOID를 SM_NULL_OID변경하고 예외
     * 발생시 이전 OID로 복원해야 합니다. 하지만 남는 로그가 redo only여서
     * undo되지않아 mTableHeader->mNullOID이 엉뚱한 값이들어있는 상태가 됩니다.
     * 코드를 삭제하는 대신에 주석처리 합니다.

    IDE_TEST( smrUpdate::setNullRow( NULL, // idvSQL
                                     sTrans,
                                     SMI_ID_TABLESPACE_SYSTEM_MEMORY_DIC,
                                     SM_MAKE_PID( mTableHeader->mSelfOID ),
                                     SM_MAKE_OFFSET( mTableHeader->mSelfOID ) + SMP_SLOT_HEADER_SIZE,
                                     SM_NULL_OID )
             != IDE_SUCCESS );

    mTableHeader->mNullOID = SM_NULL_OID;

    sState = 0;
    IDE_TEST( smmDirtyPageMgr::insDirtyPage(
                                   SMI_ID_TABLESPACE_SYSTEM_MEMORY_DIC,
                                   sCatPageID )
              != IDE_SUCCESS );
    */
    // To Fix BUG-13924
    ideLog::log( SM_TRC_LOG_LEVEL_INTERFACE,
                 SM_TRC_INTERFACE_FILE_CREATE,
                 mFile.getFileName() );

    return IDE_SUCCESS;

    IDE_EXCEPTION( err_wait_for_file_delete )
    {
        IDE_SET( ideSetErrorCode(smERR_ABORT_UnableToExecuteAlterTable,
                                 smcTable::getTableOID(mTableHeader)) );
    }
    IDE_EXCEPTION_END;

    if(sState != 0)
    {
        IDE_PUSH();
        switch( sState )
        {
            case 4:     /* 커서 close */
                IDE_ASSERT( sCursor.close() == IDE_SUCCESS );
            case 3:     /* Lob Column List 파괴 */
                IDE_ASSERT( smcTable::destLobColumnList( sLobColumnList )
                            == IDE_SUCCESS );
            case 2:     /* 백업 파일 close */
                IDE_ASSERT( finishAccessFile() == IDE_SUCCESS );

                if( idf::access(mFile.getFileName(), F_OK) == 0 )
                {
                    if( idf::unlink( mFile.getFileName() ) != 0 )
                    {
                        ideLog::log( SM_TRC_LOG_LEVEL_INTERFACE,
                                     SM_TRC_INTERFACE_FILE_UNLINK_ERROR,
                                     mFile.getFileName(), errno );
                    }
                    else
                    {
                        /* nothing to do */
                    }
                }
                else
                {
                    /* nothing to do */
                }

            case 1:
                ;
            /* BUG-34262 [SM] When alter table add/modify/drop column, backup file
             * cannot be deleted.
             * setNullRow와 동일한 이유로 주석처리 됨
                IDE_ASSERT( smmDirtyPageMgr::insDirtyPage(
                                SMI_ID_TABLESPACE_SYSTEM_MEMORY_DIC,
                                sCatPageID )
                            == IDE_SUCCESS );
            */
        }
        IDE_POP();
    }

    return IDE_FAILURE;
}

/***********************************************************************
 * Description : aDstTable에 aTableOID에 해당하는 BackupFile을 읽어서
 *               insert한다.
 *
 * aStatement       - [IN] Statement
 * aDstTable        - [IN] Restore Target Table에 대한 Table Handle
 * aTableOID        - [IN] Source Table OID
 * aSrcColumnList   - [IN] 원본 Table의 Column List
 * aBothColumnList  - [IN] Restore Target Table에 대한 Column List
 * aNewRow          - [IN] Restore Target Table에 대한 Value List
 * aIsUndo          - [IN] Undo시 호출되면 ID_TRUE, 아니면 ID_FALSE
 ***********************************************************************/
IDE_RC smiVolTableBackup::restore(void                  * aTrans,
                                  const void            * aDstTable,
                                  smOID                   aTableOID,
                                  smiColumnList         * aSrcColumnList,
                                  smiColumnList         * aBothColumnList,
                                  smiValue              * aNewRow,
                                  idBool                  aIsUndo,
                                  smiAlterTableCallBack * aCallBack)
{
    smcTableHeader            * sDstTableHeader;
    UInt                        sState      = 0;
    UInt                        sRowCount   = 0;
    UInt                        sCheckCount = 0;
    smxTrans                  * sTrans = (smxTrans*)aTrans;
    smSCN                       sSCN;
    scGRID                      sDummyGRID;
    smxTableInfo              * sTableInfo  = NULL;
    SChar*                      sInsertedRowPtr;
    smcBackupFileTail           sBackupFileTail;
    ULong                       sFenceSize;
    smiTableBackupColumnInfo  * sArrColumnInfo;
    smiTableBackupColumnInfo  * sArrLobColumnInfo;
    UInt                        sLobColumnCnt;
    UInt                        sColumnCnt;
    UInt                        sAddOIDFlag = 0;

    /* BUG-31881 [sm-mem-resource] When executing alter table in MRDB
     * and using space by other transaction,
     * The server can not do restart recovery. */
    IDU_FIT_POINT( "1.BUG-31881@smiVolTableBackup::restore" );

    SM_INIT_SCN( &sSCN );

    sDstTableHeader  = (smcTableHeader*)( (UChar*)aDstTable + SMP_SLOT_HEADER_SIZE );

    if ( aIsUndo == ID_TRUE )
    {
        sAddOIDFlag = SM_FLAG_TABLE_RESTORE_UNDO;
    }
    else
    {
        sAddOIDFlag = SM_FLAG_TABLE_RESTORE;
    }

    IDE_TEST( prepareAccessFile( ID_FALSE/*READ*/ ) != IDE_SUCCESS );
    sState = 1;

    IDE_TEST( getBackupFileTail( &sBackupFileTail ) != IDE_SUCCESS );

    IDE_TEST( checkBackupFileIsValid( aTableOID, &sBackupFileTail )
              != IDE_SUCCESS );

    mOffset = ID_SIZEOF( smcBackupFileHeader );

    /* 기록된 Column정보는 Skip한다. */
    IDE_TEST( skipColumnInfo() != IDE_SUCCESS );

    /* Max Row크기로 버퍼를 할당한다.*/
    IDE_TEST( initBuffer( sBackupFileTail.mMaxRowSize )
              != IDE_SUCCESS );
    sState = 2;

    /* PROJ-2174 Supporting LOB in the volatile tablespace*/
    IDE_TEST( makeColumnList4Res(aDstTable,
                                 aSrcColumnList,
                                 aBothColumnList,
                                 &sArrColumnInfo,
                                 &sColumnCnt,
                                 &sArrLobColumnInfo,
                                 &sLobColumnCnt )
              != IDE_SUCCESS );
    sState = 3;

    if ( aIsUndo == ID_TRUE )
    {
        /* Undo시에는 Record Count를 이 함수에서 원복시켜준다. 때문에 Insert시에
           Table Info를 넘길 필요가 없다. */

        /* Undo 시에는 Null Row를 이미 Free했기 때문에 다시 만들어
           주어야 한다.*/
        IDE_ASSERT(aSrcColumnList == aBothColumnList);

        /* PROJ-2174 Supporting LOB in the volatile tablespace*/
        IDE_TEST( readNullRowAndSet( sTrans,
                                     sDstTableHeader,
                                     sArrColumnInfo,
                                     sColumnCnt,
                                     sArrLobColumnInfo,
                                     sLobColumnCnt,
                                     aNewRow,
                                     aCallBack )
                  != IDE_SUCCESS );
    }
    else
    {
        IDE_TEST( sTrans->getTableInfo( sDstTableHeader->mSelfOID, &sTableInfo )
                  != IDE_SUCCESS );
        /* smcTable::createTable에서 Target Table생성시
           Null Row를 생성했다. 따라서 Skip한다.*/
        IDE_TEST( skipNullRow( aSrcColumnList )
                  != IDE_SUCCESS );
    }

    sFenceSize = sBackupFileTail.mSize - ID_SIZEOF(smcBackupFileTail);

    while(mOffset < sFenceSize)
    {
        if ( aCallBack != NULL )
        {
            IDE_TEST( aCallBack->initializeConvert( aCallBack->info )
                      != IDE_SUCCESS );
        }

        IDE_TEST( readRowFromBackupFile( sArrColumnInfo,
                                         sColumnCnt,
                                         aNewRow,
                                         aCallBack )
                 != IDE_SUCCESS);

        /* PROJ-1090 Function-based Index */
        if ( aCallBack != NULL )
        {
            IDE_TEST( aCallBack->calculateValue( aNewRow,
                                                 aCallBack->info )
                      != IDE_SUCCESS );
        }
        else
        {
            /* Nothing to do */
        }

        IDE_TEST( svcRecord::insertVersion( NULL,
                                            sTrans,
                                            sTableInfo,
                                            sDstTableHeader,
                                            sSCN,
                                            &sInsertedRowPtr,
                                            &sDummyGRID,
                                            aNewRow,
                                            sAddOIDFlag )
                  != IDE_SUCCESS );
        /* 실제 Row 삽입 후 Count */
        sRowCount++;

        /* PROJ-2174 Supporting LOB in the volatile tablespace */
        /* LOB Column 삽입 */
        IDE_TEST( insertLobRow( sTrans,
                                sDstTableHeader,
                                sArrLobColumnInfo,
                                sLobColumnCnt,
                                sInsertedRowPtr,
                                sAddOIDFlag )
                  != IDE_SUCCESS );

        if ( aCallBack != NULL )
        {
            // BUG-42920 DDL print data move progress
            IDE_TEST( aCallBack->printProgressLog( aCallBack->info,
                                                   ID_FALSE )
                      != IDE_SUCCESS );

            IDE_TEST( aCallBack->finalizeConvert( aCallBack->info )
                      != IDE_SUCCESS );
        }

        sCheckCount++;

        if( sCheckCount == 100 )
        {
            IDE_TEST( iduCheckSessionEvent( sTrans->mStatistics )
                      != IDE_SUCCESS );
            sCheckCount = 0;
        }
    } // end of while

    // BUG-42920 DDL print data move progress
    if ( aCallBack != NULL )
    {
        IDE_TEST( aCallBack->printProgressLog( aCallBack->info,
                                               ID_TRUE )
                  != IDE_SUCCESS );
    }
    else
    {
        // nothing to do
    }

    sState = 2;
    IDE_TEST( destColumnList4Res( sArrColumnInfo,
                                  sArrLobColumnInfo)
              != IDE_SUCCESS );

    sState = 1;
    IDE_TEST( destBuffer() != IDE_SUCCESS );

    sState = 0;
    IDE_TEST( finishAccessFile() != IDE_SUCCESS );

    if( aIsUndo == ID_TRUE )
    {
        /* BUG-18021: Record Count가 0이 아닌 Table이 Alter Table Add Column을 하다
         * 가 실패하게 되면 Record Count가 0이 됩니다.
         *
         * Rollback시에 Alter Table Add Column과 같은 경우 Table의 Record 갯수가
         * 0개로 되어 있다. 왜냐하면 Drop Table을 수행했기 때문이다. 그리고 위
         * Insert Version시 Record의 갯수는 올라가지 않는다. 때문에 이 함수가
         * Undo시에 호출이 되었다면 테이블의 레코드 갯수를 보정해야 한다. */
        IDE_TEST( smcTable::setRecordCount( sDstTableHeader,
                                            sRowCount )
                  != IDE_SUCCESS );
    }

    /* BUG-16841: [AT-F5-2]  ART sequential test중 ART /Server/mm3/
     * Statement/Rebuild/PrepareRebuild/TruncateTable/
     * truncateTable.sql에서 crash
     * restart recovery시 undo시에 refine시에 빌드되는 temporal index헤더를
     * 접근하는 경우가 발생하여 restart안되었음. restart시에
     * 이런 정보에 접근하는 것을 방지해야 한다.*/
    if( smrRecoveryMgr::isRestart() == ID_FALSE )
    {
        // Index를 삭제한다.
        IDE_TEST( smnManager::dropIndexes( sDstTableHeader )
                  != IDE_SUCCESS );

        // Restore된 Table에 대해서 Index를 재구성한다.
        IDE_TEST( smnManager::createIndexes(
                    NULL,
                    sTrans,
                    sDstTableHeader,
                    ID_FALSE, /* aIsRestartRebuild */
                    ID_FALSE,
                    NULL, /* smiSegAttr */
                    NULL) /* smiSegStorageAttr * */
                != IDE_SUCCESS );
    }

    /* BUG-42411 */
    IDE_ERROR( svrLogMgr::removeLogHereafter( sTrans->getVolatileLogEnv(),
                                              SVR_LSN_BEFORE_FIRST )
                == IDE_SUCCESS );

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    /* BUG-30457  memory volatile 테이블에 대한 alter시
     * 공간 부족으로 rollback이 부족한 상황이면 비정상
     * 종료합니다.
     * pageList를 모두 반환했으므로, 이후 대상 Table에
     * 이루어진 Insert Record에 대한 Undo는 필요 없습니다.
     * 이때 Memory Table과 달리, Volatile Table은 Vol 로그를 모두
     * 날려야 합니다.
     * Vol은 로그를 따로 관리하며, 여기에는 DML로그만 기록합니다.
     * 또한 Vol로그는 Mem로그와 독립적으로 기록하고, Mem로그를 모두
     * 수행한 후에 Vol로그만 따로 기록합니다.
     *
     * 따라서 이전 CreateTable시 삽입한 NullRow에 대한 Rollback이
     * CreateTable DDL문과 함께 같이 NTARollback되지 않습니다.
     * 따라서 모든 Vol DML을 날리기 위해 전부 지워야 합니다. */

    /* BUG-30813 [VAL] Volatile Table Restore에 실패하면
     * Volatile Log를 모두 제거해야 합니다.
     *
     * Resotre에 실패하면 무조건 Volatile Log를 제거해야 합니다.
     * Null Row를 삽입하지 않았고, Insert 한 row가 없어도
     * Volatile Log가 존재하여 svrRecoveryMgr::undo에서
     * Volatile Log를 읽어서 svcRecordUndo의 undoInsert를
     * 호출합니다. (valgrind bug로 발생)
     *
     * 따라서 Restore에 실패하면 Volatile Log를
     * 모두 제거해야 합니다. */
    IDE_PUSH();

    IDE_ASSERT( svrLogMgr::removeLogHereafter( sTrans->getVolatileLogEnv(),
                                               SVR_LSN_BEFORE_FIRST )
                == IDE_SUCCESS );

    IDE_POP();

    if(sState != 0)
    {
        IDE_PUSH();
        switch(sState)
        {
            case 3:
                IDE_ASSERT( destColumnList4Res( sArrColumnInfo,
                                                sArrLobColumnInfo )
                            == IDE_SUCCESS );
            case 2:
                IDE_ASSERT( destBuffer() == IDE_SUCCESS );
            case 1:
                IDE_ASSERT( finishAccessFile() == IDE_SUCCESS );
            default:
                break;
        }
        IDE_POP();
    }

    return IDE_FAILURE;
}

/***********************************************************************
 * Description : BackupFile로 부터 데이타를 읽어서 Value List를 구성한다.
 *
 * aSrcColumnList   - [IN] Source Table의 Column List
 * aDstColumnList   - [IN] Target Table의 Column List
 * aValue           - [IN] Value List
 * aCallBack        - [IN] Type Conversion CallBack
 ***********************************************************************/
IDE_RC smiVolTableBackup::readRowFromBackupFile(
    smiTableBackupColumnInfo * aArrColumnInfo,
    UInt                       aColumnCnt,
    smiValue                 * aArrValue,
    smiAlterTableCallBack    * aCallBack )
{
    UInt            sColumnOffset;
    smiValue*       sValue;

    smiTableBackupColumnInfo *sColumnInfo;
    smiTableBackupColumnInfo *sFence;

    sColumnOffset  = 0;

    sValue      = aArrValue;
    sColumnInfo = aArrColumnInfo;
    sFence      = sColumnInfo + aColumnCnt;

    for( ; sColumnInfo < sFence; sColumnInfo++ )
    {
        if( sColumnInfo->mIsSkip == ID_FALSE )
        {
            IDE_TEST( readColumnFromBackupFile( sColumnInfo->mSrcColumn,
                                                sValue,
                                                &sColumnOffset )
                      != IDE_SUCCESS);

            if ( aCallBack != NULL )
            {
                // src column과 dest column의 schema가 달리질 수 있으므로
                IDE_TEST( aCallBack->convertValue( NULL, /* aStatistics */
                                                   sColumnInfo->mSrcColumn,
                                                   sColumnInfo->mDestColumn,
                                                   sValue,
                                                   aCallBack->info )
                          != IDE_SUCCESS );
            }

            sValue++;
        }
        else
        {
            IDE_TEST( skipReadColumn( sColumnInfo->mSrcColumn )
                      != IDE_SUCCESS);
        }
    }

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    return IDE_FAILURE;
}

/***********************************************************************
 * Description : Backup file로 부터 aColumn이 지정하는 Column을 읽어서
 *               aValue에 저장한다.
 *
 * aColumn        - [IN] Column Pointer
 * aValue         - [IN] Value Pointer
 * aColumnOffset  - [INOUT] 1. IN: mBuffer에 이번 Column이 저장될 위치
 *                          2. OUT: mBuffer에 다음 Column이 저정될 위치
 ***********************************************************************/
IDE_RC smiVolTableBackup::readColumnFromBackupFile(const smiColumn *aColumn,
                                                   smiValue        *aValue,
                                                   UInt            *aColumnOffset)
{
    SInt sColumnType = aColumn->flag & SMI_COLUMN_TYPE_MASK;

    IDE_ASSERT( *aColumnOffset <= mBufferSize );

    aValue->value = mBuffer + *aColumnOffset;

    switch( sColumnType )
    {
        /* PROJ-2174 Supporting LOB in the volatile tablespace */
        case SMI_COLUMN_TYPE_LOB:
            /* LOB Cursor로 별도로 저장하기 때문에 Insert시
             * Empty LOB을 넣는다.*/
            aValue->length = 0;
            aValue->value = NULL;
            break;

        case SMI_COLUMN_TYPE_VARIABLE:
        case SMI_COLUMN_TYPE_VARIABLE_LARGE:
            IDE_TEST(mFile.read(mOffset, &(aValue->length), ID_SIZEOF(UInt))
                     != IDE_SUCCESS);

            mOffset += ID_SIZEOF(UInt);

            if( aValue->length == 0 )
            {
                aValue->value = NULL;
            }
            else
            {
                /* BUG-25640
                 * Variable 또는 Lob 칼럼만 존재하며 값이 Null일 경우,
                 * Row의 Value만 저장하는 mBuffer 또한 Null일 수 있다. */
                IDE_DASSERT( mBuffer != NULL );

                mFile.read(mOffset,
                           (void*)(aValue->value),
                           aValue->length);

                mOffset += aValue->length;
            }
            break;

        case SMI_COLUMN_TYPE_FIXED:
            /* BUG-25640
             * Variable 또는 Lob 칼럼만 존재하며 값이 Null일 경우,
             * Row의 Value만 저장하는 mBuffer 또한 Null일 수 있다. */
            IDE_DASSERT( mBuffer != NULL );

            aValue->length = aColumn->size;

            IDE_TEST(mFile.read(mOffset,
                                (void*)(aValue->value),
                                aColumn->size)
                     != IDE_SUCCESS);

            mOffset += aColumn->size;
            break;

        default:
            IDE_ASSERT(0);
            break;
    }

    /* BUG-25121
     * Restore시 백업파일로부터 Row를 읽습니다. 이때 칼럼별로 하나씩 읽습니다.
     * 각 칼럼은 향후 QP에게 전달될 가능성이 있기 때문에 Align에 맞지 않으면
     * Sigbus error가 납니다.
     *
     * 따라서 각 칼럼별로 8byte Align을 맞춰줍니다. 어차피 읽어드린 하나의
     * Row가 잠시 저장될 공간이기 때문에 넉넉하게 8Byte align을 맞춰도
     * 낭비가 아닙니다. */
    *aColumnOffset += idlOS::align8( aValue->length );

    IDE_ASSERT( *aColumnOffset <= mBufferSize );

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    return IDE_FAILURE;
}

/***********************************************************************
 * Description : Backup File에서 aColumn이 가리키는 데이타는 Skip한다.
 *
 * aColumn - [IN] Column Pointer
 ***********************************************************************/
IDE_RC smiVolTableBackup::skipReadColumn(const smiColumn * aColumn)
{
    SInt sColumnType = aColumn->flag & SMI_COLUMN_TYPE_MASK;
    UInt sLength;

    IDE_DASSERT( aColumn != NULL );

    switch( sColumnType )
    {
        /* PROJ-2174 Supporting LOB in the volatile tablespace */
        case SMI_COLUMN_TYPE_LOB:
            break;

        case SMI_COLUMN_TYPE_VARIABLE:
        case SMI_COLUMN_TYPE_VARIABLE_LARGE:
            IDE_TEST(mFile.read(mOffset, &sLength, ID_SIZEOF(UInt))
                     != IDE_SUCCESS);

            mOffset += ID_SIZEOF(UInt);
            mOffset += sLength;

            break;

        case SMI_COLUMN_TYPE_FIXED:
            mOffset += aColumn->size;
            break;

        default:
            IDE_ASSERT(0);
            break;
    }

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    return IDE_FAILURE;
}

/* PROJ-2174 Supporting LOB in the volatile tablespace */
/***********************************************************************
 * Description : Backup File에서 aColumn이 가리키는 데이타는 Skip한다.
 *
 * aColumn - [IN] Column Pointer
 ***********************************************************************/
IDE_RC smiVolTableBackup::skipReadLobColumn(const smiColumn * aColumn)
{
    SInt sColumnType = aColumn->flag & SMI_COLUMN_TYPE_MASK;
    UInt sLength;
    UInt sLobFlag;

    IDE_DASSERT( aColumn != NULL );

    IDE_ASSERT( sColumnType == SMI_COLUMN_TYPE_LOB );
    IDE_TEST(mFile.read(mOffset, &sLength, ID_SIZEOF(UInt))
             != IDE_SUCCESS);
    mOffset += ID_SIZEOF(UInt);

    IDE_TEST(mFile.read(mOffset, &sLobFlag, ID_SIZEOF(UInt))
             != IDE_SUCCESS);
    mOffset += ID_SIZEOF(UInt);

    mOffset += sLength;

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    return IDE_FAILURE;
}

/* PROJ-2174 Supporting LOB in the volatile tablespace */
/***********************************************************************
 * Description : aRowPtr에 있는 LOB Column을 aCursor가 가리키는
 *               Table에 삽입한다.
 *
 * aArrLobColumnInfo - [IN] 백업파일에서 읽어야 할 Lob Column정보
 * aLobColumnCnt     - [IN] 백업파일에서 읽어야 할 Lob Column 갯수
 * aRowPtr           - Insert할 Row Pointer.
 * aAddOIDFlag       - [IN] OID LIST에 추가할지 여부
 ***********************************************************************/
IDE_RC smiVolTableBackup::insertLobRow(
                            void                          * aTrans,
                            void                          * aHeader,
                            smiTableBackupColumnInfo      * aArrLobColumnInfo,
                            UInt                            aLobColumnCnt,
                            SChar                         * aRowPtr,
                            UInt                            aAddOIDFlag )
{
    UInt            sLobLen;
    UInt            sLobFlag;
    UInt            sRemainLobLen;
    UInt            sPieceSize;
    UInt            sOffset;
    smcLobDesc*     sCurLobDesc;

    smiTableBackupColumnInfo * sColumnInfo;
    smiTableBackupColumnInfo * sFence;

    IDE_DASSERT( aTrans  != NULL );
    IDE_DASSERT( aRowPtr != NULL );

    sColumnInfo = aArrLobColumnInfo;
    sFence      = sColumnInfo + aLobColumnCnt;

    for( sColumnInfo = aArrLobColumnInfo; sColumnInfo < sFence; sColumnInfo++)
    {
        if( sColumnInfo->mIsSkip == ID_TRUE )
        {
            IDE_TEST(skipReadLobColumn(sColumnInfo->mSrcColumn)
                     != IDE_SUCCESS);

        }
        else
        {
            IDE_TEST(mFile.read(mOffset, &sLobLen, ID_SIZEOF(UInt))
                     != IDE_SUCCESS);
            mOffset += ID_SIZEOF(UInt);

            IDE_TEST(mFile.read(mOffset, &sLobFlag, ID_SIZEOF(UInt))
                     != IDE_SUCCESS);
            mOffset += ID_SIZEOF(UInt);

            sRemainLobLen = sLobLen;

            if( (sLobFlag & SM_VCDESC_NULL_LOB_MASK) !=
                SM_VCDESC_NULL_LOB_TRUE )
            {
                /* BUG-25640
                 * Variable 또는 Lob 칼럼만 존재하며 값이
                 * Null일 경우, Row의 Value만 저장하는
                 * mBuffer 또한 Null일 수 있다.
                 */
                IDE_DASSERT( mBuffer != NULL );

                IDE_TEST( svcLob::reserveSpaceInternalAndLogging(
                                                      aTrans,
                                                      (smcTableHeader*)aHeader,
                                                      aRowPtr,
                                                      sColumnInfo->mDestColumn,
                                                      0,  /* aOffset */
                                                      sRemainLobLen, /*aNewSize*/
                                                      aAddOIDFlag )
                          != IDE_SUCCESS );

                sPieceSize = mBufferSize;
                sOffset    = 0;

                while(sRemainLobLen > 0)
                {
                    if(sRemainLobLen < sPieceSize)
                    {
                        sPieceSize = sRemainLobLen;
                    }

                    IDE_TEST(mFile.read(mOffset, mBuffer, sPieceSize)
                             != IDE_SUCCESS);
                    mOffset += sPieceSize;

                    IDE_TEST( svcLob::writeInternal( (UChar*)aRowPtr,
                                                     sColumnInfo->mDestColumn,
                                                     sOffset,
                                                     sPieceSize,
                                                     mBuffer )
                              != IDE_SUCCESS );

                    sOffset += sPieceSize;

                    IDE_ASSERT(sRemainLobLen - sPieceSize < sRemainLobLen);
                    sRemainLobLen -= sPieceSize;
                }
            }
            else
            {
                sCurLobDesc = smcRecord::getLOBDesc( sColumnInfo->mDestColumn,
                                                     aRowPtr );

                IDE_ERROR( (sCurLobDesc->flag & SM_VCDESC_NULL_LOB_TRUE)
                           == SM_VCDESC_NULL_LOB_TRUE );

                IDE_ERROR( sRemainLobLen == 0 );
            }
        }
    }

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    return IDE_FAILURE;
}

/***********************************************************************
 * Description : BackupFile에 File Header를 mOffset이 가리키는 위치에
 *               Write한다.
 *
 ***********************************************************************/
IDE_RC smiVolTableBackup::appendBackupFileHeader()
{
    smmMemBase            * sMemBase;
    smcBackupFileHeader     sFileHeader;

    /* BUG-16233: [Valgrind] Syscall param pwrite64(buf) points to
       uninitialised byte(s) [smcTableBackupFile.cpp:142]: smcBackupFileHeader에
       모든 Member가 초기화되지 않습니다. */
    idlOS::memset(&sFileHeader, 0, ID_SIZEOF(smcBackupFileHeader));

    sMemBase = smmDatabase::getDicMemBase();

    /*
        주의. Tablespace마다 달라질 수 있는 필드를
        이 함수에서 사용해서는 안된다.
     */

    idlOS::memset(&sFileHeader, 0x00, ID_SIZEOF(smcBackupFileHeader));

    idlOS::snprintf(sFileHeader.mType,
                    SM_TABLE_BACKUP_TYPE_SIZE,
                    SM_VOLTABLE_BACKUP_STR);

    idlOS::memcpy(sFileHeader.mProductSignature,
                  sMemBase->mProductSignature,
                  IDU_SYSTEM_INFO_LENGTH);

    idlOS::memcpy(sFileHeader.mDbname,
                  sMemBase->mDBname,
                  SM_MAX_DB_NAME);

    idlOS::memcpy((void*)&(sFileHeader.mVersionID),
                  (void*)&(sMemBase->mVersionID),
                  ID_SIZEOF(UInt));

    idlOS::memcpy((void*)&(sFileHeader.mCompileBit),
                  (void*)&(sMemBase->mCompileBit),
                  ID_SIZEOF(UInt));

    idlOS::memcpy((void*)&(sFileHeader.mBigEndian),
                  (void*)&(sMemBase->mBigEndian),
                  ID_SIZEOF(idBool));

    idlOS::memcpy((void*)&(sFileHeader.mLogSize),
                  (void*)&(sMemBase->mLogSize),
                  ID_SIZEOF(vULong));

    idlOS::memcpy((void*)&(sFileHeader.mTableOID),
                  (void*)&(mTableHeader->mSelfOID),
                  ID_SIZEOF(smOID));

    IDE_TEST(writeToBackupFile((UChar*)&sFileHeader, ID_SIZEOF(smcBackupFileHeader))
             != IDE_SUCCESS);

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    return IDE_FAILURE;
}

/***********************************************************************
 * Description : BackupFile에 File Tail을 mOffset이 가리키는 위치에
 *               Write한다.
 *
 ***********************************************************************/
IDE_RC smiVolTableBackup::appendBackupFileTail( smOID   aTableOID,
                                                ULong   aFileSize,
                                                UInt    aRowMaxSize )
{
    smcBackupFileTail sFileTail;

    /* BUG-16233: [Valgrind] Syscall param pwrite64(buf) points to
       uninitialised byte(s) [smcTableBackupFile.cpp:142]: smcBackupFileTail에
       모든 Member가 초기화되지 않습니다. */
    idlOS::memset(&sFileTail, 0, ID_SIZEOF(smcBackupFileTail));

    idlOS::memcpy(&(sFileTail.mTableOID), &aTableOID, ID_SIZEOF(smOID));
    idlOS::memcpy(&(sFileTail.mSize), &aFileSize, ID_SIZEOF(ULong));
    idlOS::memcpy(&(sFileTail.mMaxRowSize), &aRowMaxSize, ID_SIZEOF(UInt));

    IDE_TEST(writeToBackupFile(&sFileTail, ID_SIZEOF(smcBackupFileTail))
             != IDE_SUCCESS);

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    return IDE_FAILURE;
}

/* PROJ-2174 Supporting LOB in the volatile tablespace */
/***********************************************************************
 * Description : BackupFile에 mOffset이 가리키는 위치에 aRowPtr를 Write한다.
 *
 *     * Row Format
 *       Fixed Column: Data
 *       VAR, LOB    : Length(UInt) | Data
 *
 * aTableCursor - [IN]: Backup할 table에 대해 open된 table cursor
 * aRowPtr      - [IN]: Write할 row pointer
 * aRowSize     - [OUT]: File에 Write한 크기
 ***********************************************************************/
IDE_RC smiVolTableBackup::appendRow(smiTableCursor * aTableCursor,
                                    smiColumn     ** aArrLobColumn,
                                    UInt             aLobColumnCnt,
                                    SChar          * aRowPtr,
                                    UInt           * aRowSize)
{
    UInt        sColumnCnt;
    UInt        sColumnLen;
    UInt        i;
    SInt        sColumnType;
    UInt        sRowSize    = 0;
    SChar       sVarColumnData[SMP_VC_PIECE_MAX_SIZE];
    UInt        sRemainedReadSize;
    UInt        sReadSize;
    SChar*      sColumnPtr;
    UInt        sReadPos;
    UChar*      sLobBuffer      = NULL;
    idBool      sLobBufferAlloc = ID_FALSE;
    UInt        sLobBackupBufferSize;
    smcLobDesc* sLOBDesc;

    const smiColumn * sCurColumn;

    IDE_DASSERT( aTableCursor != NULL );
    IDE_DASSERT( aRowPtr      != NULL );
    IDE_DASSERT( aRowSize     != NULL );

    sColumnCnt = mTableHeader->mColumnCount;

    for( i = 0; i < sColumnCnt; i++ )
    {
        sCurColumn    = smcTable::getColumn( mTableHeader, i );
        sColumnLen    = svcRecord::getColumnLen( sCurColumn, aRowPtr );
        sColumnType = sCurColumn->flag & SMI_COLUMN_TYPE_MASK;

        switch( sColumnType )
        {
            case SMI_COLUMN_TYPE_VARIABLE:
            case SMI_COLUMN_TYPE_VARIABLE_LARGE:
                /* BUG-25121
                 * sRowSize는 순수하게 Row의 최대 크기를 알아내기 위해
                 * 사용됩니다. Row의 최대 크기를 파일에 저장하고,
                 * 이후 Restore할때 Row 임시 버퍼의 크기로 사용됩니다. */
                sRowSize += idlOS::align8( sColumnLen );

                /* Column Len : Data */
                IDE_TEST( writeToBackupFile(&sColumnLen, ID_SIZEOF(UInt))
                          != IDE_SUCCESS );

                sRemainedReadSize   = sColumnLen;
                sReadPos            = 0;

                // To fix BUG-22745
                while( sRemainedReadSize > 0 )
                {
                    sReadSize = SMP_VC_PIECE_MAX_SIZE;

                    if( sRemainedReadSize < SMP_VC_PIECE_MAX_SIZE )
                    {
                        sReadSize = sRemainedReadSize;
                    }

                    sColumnPtr = svcRecord::getVarRow( aRowPtr,
                                                       sCurColumn,
                                                       sReadPos,
                                                       &sReadSize,
                                                       (SChar*)sVarColumnData,
                                                       ID_FALSE );

                    //Codesonar
                    IDE_ASSERT( sColumnPtr != NULL );

                    IDE_TEST( writeToBackupFile( sColumnPtr, sReadSize )
                              != IDE_SUCCESS );

                    sRemainedReadSize -= sReadSize;
                    sReadPos          += sReadSize;
                }
                break;

            case SMI_COLUMN_TYPE_FIXED:
                /* BUG-25121
                 * sRowSize는 순수하게 Row의 최대 크기를 알아내기 위해
                 * 사용됩니다. Row의 최대 크기를 파일에 저장하고,
                 * 이후 Restore할때 Row 임시 버퍼의 크기로 사용됩니다. */
                sRowSize += idlOS::align8( sColumnLen );

                /* Data */
                IDE_TEST( writeToBackupFile( aRowPtr + sCurColumn->offset, sColumnLen )
                          != IDE_SUCCESS );
                break;

            default:
                IDE_ASSERT(sColumnType == SMI_COLUMN_TYPE_LOB);
                break;
        }
    }// for

    /* PROJ-2174 Supporting LOB in the volatile tablespace */
    if (aLobColumnCnt > 0)
    {
        /* BUG-25711
         * lob컬럼을 backup하기 위해 버퍼가 필요하다.
         * 메모리를 최대한 요율적으로 할당하기 위해
         * 모든 lob column들의 length를 얻어 가장 큰 컬럼에 맞게
         * 할당한다.
         * 단, lob column중 SMI_MAX_LOB_BACKUP_BUFFER_SIZE보다
         * 큰게 있으면 버퍼를 SMI_MAX_LOB_BACKUP_SIZE 만큼
         * 할당한다. */

        sLobBackupBufferSize = 0;
        for(i = 0; i < aLobColumnCnt; i++)
        {
            sCurColumn    = aArrLobColumn[i];
            sColumnLen    = svcRecord::getColumnLen(sCurColumn, aRowPtr);

            if (sColumnLen >= SMI_MAX_LOB_BACKUP_BUFFER_SIZE)
            {
                sLobBackupBufferSize = SMI_MAX_LOB_BACKUP_BUFFER_SIZE;
                break;
            }

            if (sLobBackupBufferSize < sColumnLen)
            {
                sLobBackupBufferSize = sColumnLen;
            }
        }

        /* lob 컬럼의 길이가 앞에서 계산한 lob을 제외한 row
         * 길이보다 길다. 이런경우 restore 할 때 lob restore시
         * 충분한 공간 확보를 위해 sRowSize를 재설정한다.
         * 혹은 lob을 제외한 컬럼이 하나도 없으면 sRowSize는
         * 0 이 될 것인데, 그러면 lob컬럼을 restore 할 메모리를
         * 할당할지 못하기 때문에 sRowSize를 재설정해야 한다.*/
        if (sLobBackupBufferSize > sRowSize)
        {
            sRowSize = sLobBackupBufferSize;
        }

        /* lob column length 가 0 일 수 있다.
         * 이 경우엔 메모리를 할당하지 않는다.
         * appendLobColumn() 함수내에서는 이에 대해 고려가
         * 되어 있다. */
        if (sLobBackupBufferSize > 0)
        {
            /* smiVolTableBackup_appendRow_malloc_LobBuffer.tc */
            IDU_FIT_POINT("smiVolTableBackup::appendRow::malloc::LobBuffer");
            IDE_TEST(iduMemMgr::malloc(IDU_MEM_SM_SMC,
                                       sLobBackupBufferSize,
                                       (void**)&sLobBuffer,
                                       IDU_MEM_FORCE)
                     != IDE_SUCCESS);
            sLobBufferAlloc = ID_TRUE;
        }

        for(i = 0; i < aLobColumnCnt; i++)
        {
            sCurColumn    = aArrLobColumn[i];
            sColumnLen    = svcRecord::getColumnLen(sCurColumn, aRowPtr);
            sLOBDesc      = smcRecord::getLOBDesc(sCurColumn, aRowPtr);

            /* LOB Column의 Length가 무지하게 클 수 있다.
             * 때문에 특정크기단위로 여러번 데이터를 읽어서
             * 처리해야 한다. */
            if((sCurColumn->flag & SMI_COLUMN_TYPE_MASK) == SMI_COLUMN_TYPE_LOB)
            {
                IDE_TEST(appendLobColumn(NULL, /* idvSQL* */
                                         aTableCursor,
                                         sLobBuffer,
                                         sLobBackupBufferSize,
                                         sCurColumn,
                                         sColumnLen,
                                         sLOBDesc->flag,
                                         aRowPtr)
                         != IDE_SUCCESS);
            }
        }// for

        if (sLobBufferAlloc == ID_TRUE)
        {
            sLobBufferAlloc = ID_FALSE;
            IDE_TEST(iduMemMgr::free(sLobBuffer) != IDE_SUCCESS);
        }

    }//if

    *aRowSize = sRowSize;

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    if (sLobBufferAlloc == ID_TRUE)
    {
        IDE_ASSERT(iduMemMgr::free(sLobBuffer) == IDE_SUCCESS);
    }

    return IDE_FAILURE;
}

/* PROJ-2174 Supporting LOB in the volatile tablespace */
/***********************************************************************
 * Description : Backup file에 aRow에서 aLobColumn이 가리키는 데이타를
 *               기록한다.
 *      Format: Length(UInt) | Data
 *
 * aTableCursor - [IN] Table Cursor
 * aLobColumn   - [IN] LOB Column정º??
 * aLobLen      - [IN] LOB Column길이
 * aRow         - [IN] LOB Column을 가지는 Row
 ***********************************************************************/
IDE_RC smiVolTableBackup::appendLobColumn(idvSQL          * aStatistics,
                                          smiTableCursor  * aTableCursor,
                                          UChar           * aBuffer,
                                          UInt              aBufferSize,
                                          const smiColumn * aLobColumn,
                                          UInt              aLobLen,
                                          UInt              aLobFlag,
                                          SChar           * aRow)
{
    smLobLocator    sLOBLocator;
    UInt            sLOBInfo    = 0;
    UInt            sOffset     = 0;
    UInt            sPieceSize;
    UInt            sReadLength;

    IDE_TEST( writeToBackupFile(&aLobLen, ID_SIZEOF(UInt))
              != IDE_SUCCESS );

    IDE_TEST( writeToBackupFile(&aLobFlag, ID_SIZEOF(UInt))
              != IDE_SUCCESS );

    IDE_ASSERT(smiLob::openLobCursorWithRow(aTableCursor,
                                            aRow,
                                            aLobColumn,
                                            sLOBInfo,
                                            SMI_LOB_READ_MODE,
                                            &sLOBLocator)
               == IDE_SUCCESS);

    sPieceSize = aBufferSize;

    while(aLobLen > 0)
    {
        IDE_ASSERT(aBuffer != NULL);

        if(aLobLen < sPieceSize)
        {
            sPieceSize = aLobLen;
        }

        IDE_ASSERT(smiLob::read(aStatistics,
                                sLOBLocator,
                                sOffset,
                                sPieceSize,
                                aBuffer,
                                &sReadLength)
                   == IDE_SUCCESS);

        IDE_TEST( writeToBackupFile(aBuffer, sReadLength)
                  != IDE_SUCCESS );

        sOffset += sPieceSize;
        aLobLen -= sPieceSize;
    }

    IDE_TEST(smiLob::closeLobCursor( aStatistics, sLOBLocator )
             != IDE_SUCCESS);

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    return IDE_FAILURE;
}

/***********************************************************************
 * Description : aNeedSpace공간이 생길때까지 기다린다.
 *
 * aNeedSpace - [IN] 필요한 디스크 공간(Byte)
 ***********************************************************************/
IDE_RC smiVolTableBackup::waitForSpace(UInt aNeedSpace)
{
    SInt sSystemErrno;

    sSystemErrno = ideGetSystemErrno();

    IDE_TEST(sSystemErrno != 0 && sSystemErrno != ENOSPC);

    while (idlVA::getDiskFreeSpace(smcTable::getBackupDir()) < aNeedSpace)
    {
        gSmiGlobalCallBackList.setEmergencyFunc(SMI_EMERGENCY_DB_SET);
        if (smrRecoveryMgr::isFinish() == ID_TRUE)
        {
            ideLog::log(SM_TRC_LOG_LEVEL_FATAL,
                        SM_TRC_INTERFACE_WAITFOR_FATAL1);
            idlOS::exit(0);
        }
        else
        {
            IDE_WARNING(SM_TRC_LOG_LEVEL_WARNNING,
                        SM_TRC_INTERFACE_WAITFOR_FATAL2);
            idlOS::sleep(2);
        }
        gSmiGlobalCallBackList.clrEmergencyFunc(SMI_EMERGENCY_DB_CLR);
    }
    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    return IDE_FAILURE;

}

/***********************************************************************
 * Description : aTableOID 에 해당하는 백업 파일이 올바른지 Check한다.
 *
 * aTableOID - [IN] Table OID
 * aFileTail - [IN] File Tail
 ***********************************************************************/
IDE_RC smiVolTableBackup::checkBackupFileIsValid(smOID               aTableOID,
                                                 smcBackupFileTail * aFileTail)
{
    smcBackupFileHeader   sFileHeader;
    smmMemBase          * sMemBase;
    ULong                 sFileSize = 0;

    sMemBase = smmDatabase::getDicMemBase();

    IDE_TEST(mFile.read(0, (void*)&sFileHeader, ID_SIZEOF(smcBackupFileHeader))
             != IDE_SUCCESS);

    IDE_TEST_RAISE(0 != idlOS::strncmp(sFileHeader.mType,
                                       SM_VOLTABLE_BACKUP_STR,
                                       SM_TABLE_BACKUP_TYPE_SIZE),
                   err_invalid_backupfile);

    IDE_TEST_RAISE(idlOS::memcmp(sFileHeader.mProductSignature, sMemBase->mProductSignature,
                                 IDU_SYSTEM_INFO_LENGTH) != 0, err_invalid_backupfile);

    IDE_TEST_RAISE(idlOS::memcmp(sFileHeader.mDbname,
                                 sMemBase->mDBname,
                                 SM_MAX_DB_NAME) != 0,
                   err_invalid_backupfile);

    IDE_TEST_RAISE(sFileHeader.mVersionID != sMemBase->mVersionID,
                   err_invalid_backupfile);

    IDE_TEST_RAISE(sFileHeader.mCompileBit != sMemBase->mCompileBit,
                   err_invalid_backupfile);

    IDE_TEST_RAISE(sFileHeader.mBigEndian != sMemBase->mBigEndian,
                   err_invalid_backupfile);

    IDE_TEST_RAISE(aFileTail->mTableOID != aTableOID,
                   err_invalid_backupfile);

    IDE_TEST(mFile.getFileSize(&sFileSize) != IDE_SUCCESS);

    IDE_TEST_RAISE(aFileTail->mSize != sFileSize,
                   err_invalid_backupfile);

    IDE_TEST_RAISE(aFileTail->mTableOID != aTableOID,
                   err_invalid_backupfile);

    return IDE_SUCCESS;

    IDE_EXCEPTION(err_invalid_backupfile);
    {
        IDE_SET(ideSetErrorCode(smERR_ABORT_InvalidBackupFile, mFile.getFileName()));
    }
    IDE_EXCEPTION_END;

    return IDE_FAILURE;
}

/***********************************************************************
 * Description : 백업 파일의 Tail을 가져온다.
 *
 * aBackupFileTail - [OUT] 백업파일 Tail
 ***********************************************************************/
IDE_RC smiVolTableBackup::getBackupFileTail(smcBackupFileTail * aBackupFileTail)
{
    ULong sFileSize = 0;

    IDE_TEST(mFile.getFileSize(&sFileSize) != IDE_SUCCESS);
    IDE_TEST(mFile.read(sFileSize - ID_SIZEOF(smcBackupFileTail),
                        (void *)aBackupFileTail,
                        ID_SIZEOF(smcBackupFileTail))
             != IDE_SUCCESS);

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    return IDE_FAILURE;
}

/* PROJ-2174 Supporting LOB in the volatile tablespace */
/***********************************************************************
 * Description : 백업 파일에서 Null Row를 읽어서 aTableHeader가
 *               가리키는 테이블에 삽입하고 NULL Row로 Setting한다.
 *               주의 : UNDO시에만 사용되는 함수이다.
 *
 * aTrans       - [IN] Transaction Pointer
 * aTableInfo   - [IN] Table Info
 * aTableHeader - [IN] Table Header
 * aColumnList  - [IN] Column List
 * aValueList   - [IN] Value List
 ***********************************************************************/
IDE_RC smiVolTableBackup::readNullRowAndSet( void                     * aTrans,
                                             void                     * aTableHeader,
                                             smiTableBackupColumnInfo * aArrColumnInfo,
                                             UInt                       aColumnCnt,
                                             smiTableBackupColumnInfo * aArrLobColumnInfo,
                                             UInt                       aLobColumnCnt,
                                             smiValue                 * aValueList,
                                             smiAlterTableCallBack    * aCallBack )
{
    smSCN   sNullRowSCN;
    smOID   sNullRowOID;
    SChar * sInsertedRowPtr = NULL;

    smcTableHeader * sTableHeader = (smcTableHeader*)aTableHeader;

    SM_SET_SCN_NULL_ROW( &sNullRowSCN );

    if ( aCallBack != NULL )
    {
        IDE_TEST( aCallBack->initializeConvert( aCallBack->info )
                  != IDE_SUCCESS );
    }

    IDE_TEST(readRowFromBackupFile(aArrColumnInfo,
                                   aColumnCnt,
                                   aValueList,
                                   aCallBack )
             != IDE_SUCCESS);

    IDE_TEST( svcRecord::makeNullRow( aTrans,
                                      sTableHeader,
                                      sNullRowSCN,
                                      aValueList,
                                      SM_FLAG_MAKE_NULLROW_UNDO,
                                      &sNullRowOID )
              != IDE_SUCCESS );

    /* PROJ-2174 Supporting LOB in the volatile tablespace */
    IDE_TEST( smmManager::getOIDPtr( sTableHeader->mSpaceID,
                                     sNullRowOID,
                                     (void**)&sInsertedRowPtr)
              != IDE_SUCCESS );

    /* LOB Column 삽입 */
    IDE_TEST(insertLobRow(aTrans,
                          sTableHeader,
                          aArrLobColumnInfo,
                          aLobColumnCnt,
                          sInsertedRowPtr,
                          SM_FLAG_MAKE_NULLROW_UNDO)
            != IDE_SUCCESS);

    /*첫번째 Row는 Null Row이다.*/
    IDE_TEST( smcTable::setNullRow(aTrans,
                                   sTableHeader,
                                   SMI_GET_TABLE_TYPE( sTableHeader ),
                                   &sNullRowOID)
              != IDE_SUCCESS );

    if ( aCallBack != NULL )
    {
        IDE_TEST( aCallBack->finalizeConvert( aCallBack->info )
                  != IDE_SUCCESS );
    }

    return IDE_SUCCESS;
    IDE_EXCEPTION_END;
    return IDE_FAILURE;
}

/***********************************************************************
 * Description : Backup File에서 NULL값을 읽지 않고 Skip하게 한다.
 *
 * aColumnList - [IN] Table의 Column List
 ***********************************************************************/
IDE_RC smiVolTableBackup::skipNullRow(smiColumnList * aColumnList)
{
    SInt            sColumnType;
    smiColumnList * sCurColumnList = NULL;
    UInt            sColLen;
    UInt            sLobFlag;

    IDE_DASSERT( aColumnList != NULL );

    sCurColumnList  = aColumnList;

    while(sCurColumnList != NULL)
    {
        sColumnType =
            sCurColumnList->column->flag & SMI_COLUMN_TYPE_MASK;

        switch( sColumnType )
        {
            case SMI_COLUMN_TYPE_VARIABLE:
            case SMI_COLUMN_TYPE_VARIABLE_LARGE:
                IDE_TEST(mFile.read(mOffset, &sColLen, ID_SIZEOF(UInt))
                         != IDE_SUCCESS);

                mOffset += ID_SIZEOF(UInt);
                mOffset += sColLen;
                break;

            case SMI_COLUMN_TYPE_FIXED:
                mOffset += sCurColumnList->column->size;
                break;

            default:
                IDE_ASSERT(sColumnType == SMI_COLUMN_TYPE_LOB);
                break;
        }

        sCurColumnList = sCurColumnList->next;
    }

    sCurColumnList  = aColumnList;

    while(sCurColumnList != NULL)
    {
        sColumnType =
            sCurColumnList->column->flag & SMI_COLUMN_TYPE_MASK;

        /* PROJ-2174 Supporting LOB in the volatile tablespace */
        if( sColumnType == SMI_COLUMN_TYPE_LOB )
        {
            IDE_TEST(mFile.read(mOffset, &sColLen, ID_SIZEOF(UInt))
                     != IDE_SUCCESS );
            mOffset += ID_SIZEOF(UInt);

            IDE_TEST(mFile.read(mOffset, &sLobFlag, ID_SIZEOF(UInt))
                     != IDE_SUCCESS);
            mOffset += ID_SIZEOF(UInt);

            mOffset += sColLen;
            /* Caution!!: LOB Column의 Null값은 Length가 0이다. 하지만 그것은
             * MT가 정하는 것이므로 나중에 바뀔수 있다. 일단은 정확성 Check를
             * 위해서 ASSERT를 건다. Null값이 바뀌면 이부분을 수정해야 한다.*/
            IDE_ASSERT(sColLen == 0);
        }

        sCurColumnList = sCurColumnList->next;
    }

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    return IDE_FAILURE;
}

/* PROJ-2174 Supporting LOB in the volatile tablespace */
/***********************************************************************
 * Description : Column List에 할당된 메모리를 반납한다.
 *
 * aSrcColumnList    - [IN] Source Table Column List
 * aBothColumnList   - [IN] Source Table과 Destination Table에 공통된 Source Table Column List
 * aArrColumnInfo    - [OUT] 백업파일에서 읽어야 할 Column정보
 * aColumnCnt        - [OUT] 컬럼 갯수
 *
 * aArrLobColumnInfo - [OUT] 백업파일에서 읽어야 할 Lob Column정보
 * aLobColumnCnt     - [OUT] Lob 컬럼 갯수
 ***********************************************************************/
IDE_RC smiVolTableBackup::makeColumnList4Res(const void                * aDstTable,
                                             smiColumnList             * aSrcColumnList,
                                             smiColumnList             * aBothColumnList,
                                             smiTableBackupColumnInfo ** aArrColumnInfo,
                                             UInt                      * aColumnCnt,
                                             smiTableBackupColumnInfo ** aArrLobColumnInfo,
                                             UInt                      * aLobColumnCnt)

{
    smiTableBackupColumnInfo  * sArrColumnInfo      = NULL;
    smiTableBackupColumnInfo  * sArrLobColumnInfo   = NULL;

    smiColumnList   * sSrcColumnList    = NULL;
    smiColumnList   * sBothColumnList   = NULL;
    const smiColumn * sCurColumn        = NULL;
    SInt              sColumnType;
    UInt              sColumnCnt = smcTable::getColumnCount(mTableHeader);
    UInt              sLobColumnCnt = smcTable::getLobColumnCount(mTableHeader);
    UInt              i, j;
    smcTableHeader  * sDstTableHeader;
    UInt              sColumnIdx        = 0;

    sDstTableHeader  = (smcTableHeader*)( (UChar*)aDstTable + SMP_SLOT_HEADER_SIZE );

    *aColumnCnt     = sColumnCnt;
    *aLobColumnCnt  = sLobColumnCnt;

    *aArrColumnInfo     = NULL;
    *aArrLobColumnInfo  = NULL;

    if( sColumnCnt != 0 )
    {
        /* smiVolTableBackup_makeColumnList4Res_malloc_ArrColumnInfo.tc */
        IDU_FIT_POINT("smiVolTableBackup::makeColumnList4Res::malloc::ArrColumnInfo");
        IDE_TEST(iduMemMgr::malloc(
                     IDU_MEM_SM_SMC,
                     (ULong)sColumnCnt *
                     ID_SIZEOF(smiTableBackupColumnInfo),
                     (void**)aArrColumnInfo,
                     IDU_MEM_FORCE)
                 != IDE_SUCCESS);
        sArrColumnInfo = *aArrColumnInfo;
    }

    if ( sLobColumnCnt != 0 )
    {
        /* smiVolTableBackup_makeColumnList4Res_malloc_ArrLobColumnInfo */
        IDU_FIT_POINT("smiVolTableBackup::makeColumnList4Res::malloc::ArrLobColumnInfo");
        IDE_TEST(iduMemMgr::malloc(
                     IDU_MEM_SM_SMC,
                     (ULong)sLobColumnCnt *
                     ID_SIZEOF(smiTableBackupColumnInfo),
                     (void**)aArrLobColumnInfo,
                     IDU_MEM_FORCE)
                 != IDE_SUCCESS);
        sArrLobColumnInfo = *aArrLobColumnInfo;
    }

    sSrcColumnList  = aSrcColumnList;
    sBothColumnList  = aBothColumnList;

    sCurColumn  = smcTable::getColumn(sDstTableHeader, sColumnIdx);
    sColumnIdx++;

    i = 0;
    j = 0;
    while( sSrcColumnList != NULL )
    {
        sColumnType =
            sSrcColumnList->column->flag & SMI_COLUMN_TYPE_MASK;

        IDE_ASSERT( sArrColumnInfo != NULL );

        sArrColumnInfo[i].mIsSkip    = ID_TRUE;
        sArrColumnInfo[i].mSrcColumn = sSrcColumnList->column;

        if( sColumnType == SMI_COLUMN_TYPE_LOB )
        {
            IDE_ASSERT( sArrLobColumnInfo != NULL );

            sArrLobColumnInfo[j].mSrcColumn = sSrcColumnList->column;
            sArrLobColumnInfo[j].mIsSkip    = ID_TRUE;
        }

        if ( sCurColumn != NULL )
        {
            if ( sSrcColumnList->column->id == sBothColumnList->column->id )
            {
                sArrColumnInfo[i].mDestColumn = sCurColumn;
                sArrColumnInfo[i].mIsSkip     = ID_FALSE;

                if(sColumnType == SMI_COLUMN_TYPE_LOB)
                {
                    sArrLobColumnInfo[j].mIsSkip     = ID_FALSE;
                    sArrLobColumnInfo[j].mDestColumn = sCurColumn;
                }

                if( sColumnIdx < smcTable::getColumnCount(sDstTableHeader) )
                {
                    sCurColumn  = smcTable::getColumn(sDstTableHeader, sColumnIdx);
                }
                else
                {
                    sCurColumn = NULL;
                }
                sColumnIdx++;
                sBothColumnList = sBothColumnList->next;
            }
        }

        if(sColumnType == SMI_COLUMN_TYPE_LOB)
        {
            j++;
        }

        i++;
        sSrcColumnList = sSrcColumnList->next;
    }

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    if( *aArrColumnInfo != NULL )
    {
        IDE_PUSH();
        (void)iduMemMgr::free(*aArrColumnInfo);
        IDE_POP();
    }

    if( *aArrLobColumnInfo != NULL )
    {
        IDE_PUSH();
        (void)iduMemMgr::free(*aArrLobColumnInfo);
        IDE_POP();
    }

    return IDE_FAILURE;
}

/* PROJ-2174 Supporting LOB in the volatile tablespace */
/***********************************************************************
 * Description : Column List에 할당된 메모리를 반납한다.
 *
 * aArrColumn    - [IN] Column List
 * aArrLobColumn - [IN] Lob Column List
 ***********************************************************************/
IDE_RC smiVolTableBackup::destColumnList4Res( void    * aArrColumn,
                                              void    * aArrLobColumn )
{
    if( aArrColumn != NULL )
    {
        IDE_ASSERT( iduMemMgr::free(aArrColumn)
                    == IDE_SUCCESS );
    }

    if( aArrLobColumn != NULL )
    {
        IDE_ASSERT( iduMemMgr::free(aArrLobColumn)
                    == IDE_SUCCESS );
    }

    return IDE_SUCCESS;
}

/***********************************************************************
 * Description : Column List를 File Header다음에 기록한다.
 ***********************************************************************/
IDE_RC smiVolTableBackup::appendTableColumnInfo()
{
    UInt  sColumnCnt = smcTable::getColumnCount(mTableHeader);
    UInt  i;
    const smiColumn * sColumn;

    IDE_TEST(writeToBackupFile((UChar*)&sColumnCnt, ID_SIZEOF(UInt))
             != IDE_SUCCESS);

    for( i = 0; i < sColumnCnt; i++ )
    {
        sColumn = smcTable::getColumn( mTableHeader, i );

        IDE_TEST(writeToBackupFile((UChar*)sColumn, ID_SIZEOF(smiColumn))
                 != IDE_SUCCESS);
    }

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    return IDE_FAILURE;
}

/***********************************************************************
 * Description : Restore시 기록된 Column List를 skip한다.
 ***********************************************************************/
IDE_RC smiVolTableBackup::skipColumnInfo()
{
    UInt sColumnCnt;

    IDE_TEST(mFile.read(mOffset, &sColumnCnt, ID_SIZEOF(UInt))
             != IDE_SUCCESS);
    mOffset += ID_SIZEOF(UInt);

    mOffset += ( sColumnCnt * ID_SIZEOF(smiColumn));

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    return IDE_FAILURE;
}

/***********************************************************************
 * Description : Filename에 해당하는 파일을 Dump한다.
 *
 * aFilename : TableBackupFile을 Dump한다.
 *
 * cf)본 함수는 사용되고 있지 않음.
 ***********************************************************************/
IDE_RC smiVolTableBackup::dump(SChar *aFilename)
{
    ULong       sOffset     = 0;
    UInt        sColumnCnt;
    smiColumn * sColumnList;
    ULong       sFileSize = 0;
    ULong       sFenceSize;
    SInt        sColumnType;
    UInt        i;
    UInt        sSize;
    ULong       sRowCnt;

    smcTableBackupFile sFile;   //Backup File

    IDE_ASSERT(sFile.initialize(aFilename)
               == IDE_SUCCESS);

    IDE_ASSERT(sFile.open(ID_FALSE/*Read*/) == IDE_SUCCESS);

    IDE_ASSERT(sFile.getFileSize(&sFileSize) == IDE_SUCCESS);

    sOffset += ID_SIZEOF(smcBackupFileHeader);

    sFenceSize = sFileSize - ID_SIZEOF(smcBackupFileTail);

    IDE_ASSERT(sFile.read( sOffset, &sColumnCnt, ID_SIZEOF(UInt))
               == IDE_SUCCESS);
    sOffset += ID_SIZEOF(UInt);

    IDE_ASSERT(iduMemMgr::malloc(
                   IDU_MEM_SM_SMI,
                   (ULong)ID_SIZEOF(smiColumn) * sColumnCnt,
                   (void **)&sColumnList,
                   IDU_MEM_FORCE)
               == IDE_SUCCESS);

    IDE_ASSERT(sFile.read( sOffset, sColumnList, (size_t)ID_SIZEOF(smiColumn) * sColumnCnt)
               == IDE_SUCCESS);

    sOffset += (sColumnCnt * ID_SIZEOF(smiColumn));
    sRowCnt = 0;

    while( sOffset < sFenceSize)
    {
        idlOS::printf(" #%"ID_UINT32_FMT":", sRowCnt);
        for(i = 0; i < sColumnCnt; i++)
        {
            sColumnType = sColumnList[i].flag & SMI_COLUMN_TYPE_MASK;
            switch(sColumnType)
            {
                case SMI_COLUMN_TYPE_VARIABLE:
                case SMI_COLUMN_TYPE_VARIABLE_LARGE:
                    IDE_ASSERT(sFile.read( sOffset, &sSize, ID_SIZEOF(UInt))
                               == IDE_SUCCESS);
                    sOffset += ID_SIZEOF(UInt);

                    idlOS::printf(" VAR:%"ID_UINT32_FMT"", sSize);
                    sOffset += sSize;
                    break;

                case SMI_COLUMN_TYPE_FIXED:
                    idlOS::printf(" Fixed:%"ID_UINT32_FMT"", sColumnList[i].size);
                    sOffset += sColumnList[i].size;
                    break;

                default:
                    break;
            }
        }

        /* PROJ-2174 Supporting LOB in the volatile tablespace */
        for( i = 0 ; i < sColumnCnt ; i++ )
        {
            sColumnType = sColumnList[i].flag & SMI_COLUMN_TYPE_MASK;

        }

        sRowCnt++;

        idlOS::printf("\n");
    }

    IDE_ASSERT(iduMemMgr::free(sColumnList) == IDE_SUCCESS);

    idlOS::fflush(NULL);

    IDE_ASSERT(sFile.close()    == IDE_SUCCESS);
    IDE_ASSERT(sFile.destroy()  == IDE_SUCCESS);

    return IDE_SUCCESS;
}

IDE_RC smiVolTableBackup::isBackupFile(SChar *aFilename, idBool *aCheck)
{
    smmMemBase*            sMemBase;
    smcTableBackupFile     sFile;   //Backup File
    smcBackupFileHeader    sFileHeader;
    UInt                   sState = 0;
    idBool                 sCheck = ID_TRUE;

    sMemBase = smmDatabase::getDicMemBase();

    IDE_TEST(sFile.initialize(aFilename)
             != IDE_SUCCESS);
    sState = 1;

    IDE_TEST(sFile.open(ID_FALSE/*Read*/) != IDE_SUCCESS);
    sState = 2;

    IDE_TEST(sFile.read(0, (void*)&sFileHeader,
                        ID_SIZEOF(smcBackupFileHeader))
             != IDE_SUCCESS);

    if(0 != idlOS::strncmp(sFileHeader.mType,
                           SM_VOLTABLE_BACKUP_STR,
                           SM_TABLE_BACKUP_TYPE_SIZE))
    {
        sCheck = ID_FALSE;
    }
    else if(0 != idlOS::memcmp(sFileHeader.mProductSignature,
                          sMemBase->mProductSignature,
                          IDU_SYSTEM_INFO_LENGTH))
    {
        sCheck = ID_FALSE;
    }
    else if(0 != idlOS::memcmp(sFileHeader.mDbname,
                          sMemBase->mDBname,
                          SM_MAX_DB_NAME))
    {
        sCheck = ID_FALSE;
    }
    else if(sFileHeader.mVersionID != sMemBase->mVersionID)
    {
        sCheck = ID_FALSE;
    }
    else if(sFileHeader.mCompileBit != sMemBase->mCompileBit)
    {
        sCheck = ID_FALSE;
    }
    else if(sFileHeader.mBigEndian != sMemBase->mBigEndian)
    {
        sCheck = ID_FALSE;
    }

    *aCheck = sCheck;

    sState = 1;
    IDE_TEST(sFile.close() != IDE_SUCCESS);
    sState = 0;
    IDE_TEST(sFile.destroy() != IDE_SUCCESS);

    return IDE_SUCCESS;

    IDE_EXCEPTION_END;

    *aCheck = ID_FALSE;

    switch(sState)
    {
        case 2:
            sFile.close();
        case 1:
            sFile.destroy();
        default:
            break;
    }

    return IDE_FAILURE;

}


int Q3WidgetStack::id(QWidget * widget) const
{
    if (!widget)
        return -1;

    Q3IntDictIterator<QWidget> it(*dict);
    while (it.current() && it.current() != widget)
        ++it;
    return it.current() == widget ? it.currentKey() : -1;
}

/****************************************************************************
**
**
** This file is part of the Qt3Support module of the Qt Toolkit.
**
**
****************************************************************************/

#include "q3widgetstack.h"
#include "qlayout.h"
#include "private/qlayoutengine_p.h"
#include "qapplication.h"
#include "qpainter.h"

QT_BEGIN_NAMESPACE

using namespace Qt;

class Q3WidgetStackPrivate {
public:
    class Invisible: public QWidget
    {
    public:
	    Invisible(Q3WidgetStack * parent): QWidget(parent, "qt_invisible_widgetstack")
	    {
                setBackgroundMode(NoBackground);
	    }
	    const char * className() const
	    {
	        return "Q3WidgetStackPrivate::Invisible";
	    }
    protected:
            void paintEvent(QPaintEvent *)
            {
                QPainter(this).eraseRect(rect());
            }
    };

    int nextNegativeID;
    int nextPositiveID;
};

/*!
    \class Q3WidgetStack
    \brief The Q3WidgetStack class provides a stack of widgets of which
    only the top widget is user-visible.

    \compat

    The application programmer can move any widget to the top of the
    stack at any time using raiseWidget(), and add or remove widgets
    using addWidget() and removeWidget(). It is not sufficient to pass
    the widget stack as parent to a widget which should be inserted into
    the widgetstack.

    visibleWidget() is the \e get equivalent of raiseWidget(); it
    returns a pointer to the widget that is currently at the top of
    the stack.

    Q3WidgetStack also provides the ability to manipulate widgets
    through application-specified integer IDs. You can also translate
    from widget pointers to IDs using id() and from IDs to widget
    pointers using widget(). These numeric IDs are unique (per
    Q3WidgetStack, not globally), but Q3WidgetStack does not attach any
    additional meaning to them.

    The default widget stack is frameless, but you can use the usual
    Q3Frame functions (such as setFrameStyle()) to add a frame.

    Q3WidgetStack provides a signal, aboutToShow(), which is emitted
    just before a managed widget is shown.

    \sa Q3TabDialog QTabWidget QTabBar Q3Frame
*/

/*!
  Constructs an empty widget stack.

  The \a parent, \a name and \a f arguments are passed to the Q3Frame
  constructor.
*/
Q3WidgetStack::Q3WidgetStack(QWidget * parent, const char *name, Qt::WindowFlags f)
    : Q3Frame(parent, name, f) //## merge constructors in 4.0
{
    init();
}

void Q3WidgetStack::init()
{
   d = new Q3WidgetStackPrivate();
   d->nextNegativeID = -2;
   d->nextPositiveID = 0;
   dict = new Q3IntDict<QWidget>;
   focusWidgets = 0;
   topWidget = 0;
   invisible = 0;
   invisible = new Q3WidgetStackPrivate::Invisible(this);
   invisible->hide();
}

/*!
    Destroys the object and frees any allocated resources.
*/

Q3WidgetStack::~Q3WidgetStack()
{
    delete focusWidgets;
    delete d;
    delete dict;
}

/*!
    Adds widget \a w to this stack of widgets, with ID \a id.

    If you pass an id \>= 0 this ID is used. If you pass an \a id of
    -1 (the default), the widgets will be numbered automatically. If
    you pass -2 a unique negative integer will be generated. No widget
    has an ID of -1. Returns the ID or -1 on failure (e.g. \a w is 0).

    If you pass an id that is already used, then a unique negative
    integer will be generated to prevent two widgets having the same
    id.

    If \a w already exists in the stack the widget will be removed first.

    If \a w is not a child of this Q3WidgetStack moves it using
    reparent().
*/

int Q3WidgetStack::addWidget(QWidget * w, int id)
{
    if (!w || w == invisible || invisible == 0)
        return -1;

    // prevent duplicates
    removeWidget(w);

    if (id >= 0 && dict->find(id))
        id = -2;
    if (id < -1)
        id = d->nextNegativeID--;
    else if (id == -1)
        id = d->nextPositiveID++;
    else
        d->nextPositiveID = qMax(d->nextPositiveID, id + 1);

    dict->insert(id, w);

    // preserve existing focus
    QWidget * f = w->focusWidget();
    while(f && f != w)
        f = f->parentWidget();
    if (f) {
        if (!focusWidgets)
            focusWidgets = new Q3PtrDict<QWidget>(17);
        focusWidgets->replace(w, w->focusWidget());
    }

    w->hide();
    if (w->parent() != this)
        w->reparent(this, contentsRect().topLeft(), false);
    w->setGeometry(contentsRect());
    updateGeometry();
    return id;
}

/*!
    Removes widget \a w from this stack of widgets. Does not delete \a
    w. If \a w is the currently visible widget, no other widget is
    substituted.

    \sa visibleWidget() raiseWidget()
*/

void Q3WidgetStack::removeWidget(QWidget * w)
{
    int i;
    if (!w || (i = id(w)) == -1)
        return ;

    dict->take(i);
    if (w == topWidget)
        topWidget = 0;
    if (dict->isEmpty())
        invisible->hide(); // let background shine through again
    updateGeometry();
}

/*!
    Raises the widget with ID \a id to the top of the widget stack.

    \sa visibleWidget()
*/

void Q3WidgetStack::raiseWidget(int id)
{
    if (id == -1)
        return;
    QWidget * w = dict->find(id);
    if (w)
        raiseWidget(w);
}

static bool isChildOf(QWidget* child, QWidget *parent)
{
    if (!child)
        return false;
    QObjectList list = parent->children();
    for (int i = 0; i < list.size(); ++i) {
        QObject *obj = list.at(i);
        if (!obj->isWidgetType())
            continue;
        QWidget *widget = static_cast<QWidget *>(obj);
        if (!widget->isWindow())
            continue;
        if (widget == child || isChildOf(child, widget))
            return true;
    }
    return false;
}

/*!
    \overload

    Raises widget \a w to the top of the widget stack.
*/

void Q3WidgetStack::raiseWidget(QWidget *w)
{
    if (!w || w == invisible || w->parent() != this || w == topWidget)
        return;

    if (id(w) == -1)
        addWidget(w);
    if (!isVisible()) {
        topWidget = w;
        return;
    }

    if (w->maximumSize().width() < invisible->width()
        || w->maximumSize().height() < invisible->height())
        invisible->setBackgroundMode(backgroundMode());
    else if (invisible->backgroundMode() != NoBackground)
        invisible->setBackgroundMode(NoBackground);

    if (invisible->isHidden()) {
        invisible->setGeometry(contentsRect());
        invisible->lower();
        invisible->show();
        QApplication::sendPostedEvents(invisible, QEvent::ShowWindowRequest);
    }

    // try to move focus onto the incoming widget if focus
    // was somewhere on the outgoing widget.
    if (topWidget) {
        QWidget * fw = window()->focusWidget();
        if (topWidget->isAncestorOf(fw)) { // focus was on old page
            // look for the best focus widget we can find
            QWidget *p = w->focusWidget();
            if (!p) {
                // second best == first child widget in the focus chain
                QWidget *i = fw;
                while ((i = i->nextInFocusChain()) != fw) {
                    if (((i->focusPolicy() & Qt::TabFocus) == Qt::TabFocus)
                        && !i->focusProxy() && i->isVisibleTo(w) && i->isEnabled()
                        && w->isAncestorOf(i)) {
                        p = i;
                        break;
                    }
                }
            }
            if (p)
                p->setFocus();
        } else {
            // the focus wasn't on the old page, so we have to ensure focus doesn't go to
            // the widget in the page that last had focus when we show the page again.
            QWidget *oldfw = topWidget->focusWidget();
            if (oldfw)
                oldfw->clearFocus();
        }
    }

    if (isVisible()) {
        emit aboutToShow(w);
        int i = id(w);
        if (i != -1)
            emit aboutToShow(i);
    }

    topWidget = w;

    QObjectList c = children();
    for (int i = 0; i < c.size(); ++i) {
        QObject * o = c.at(i);
        if (o->isWidgetType() && o != w && o != invisible)
            static_cast<QWidget *>(o)->hide();
    }

    w->setGeometry(invisible->geometry());
    w->show();
}

/*!
    \reimp
*/

void Q3WidgetStack::frameChanged()
{
    Q3Frame::frameChanged();
    setChildGeometries();
}

/*!
    \internal
*/

void Q3WidgetStack::setFrameRect(const QRect & r)
{
    // ### this function used to be virtual in QFrame in Qt 3; it is no longer virtual in Qt 4
    Q3Frame::setFrameRect(r);
    setChildGeometries();
}

/*!
    Fixes up the children's geometries.
*/

void Q3WidgetStack::setChildGeometries()
{
    invisible->setGeometry(contentsRect());
    if (topWidget)
        topWidget->setGeometry(invisible->geometry());
}

/*!
    \reimp
*/
void Q3WidgetStack::setVisible(bool visible)
{
    if (visible) {
        //  Reimplemented in order to set the children's geometries
        //  appropriately and to pick the first widget as d->topWidget if no
        //  topwidget was defined
        QObjectList c = children();
        if (!isVisible() && !c.isEmpty()) {
            for (int i = 0; i < c.size(); ++i) {
                QObject * o = c.at(i);
                if (o->isWidgetType()) {
                    if (!topWidget && o != invisible)
                        topWidget = static_cast<QWidget*>(o);
                    if (o == topWidget)
                        static_cast<QWidget *>(o)->show();
                    else
                        static_cast<QWidget *>(o)->hide();
                }
            }
            setChildGeometries();
        }
    }
    Q3Frame::setVisible(visible);
}

/*!
    Returns the widget with ID \a id. Returns 0 if this widget stack
    does not manage a widget with ID \a id.

    \sa id() addWidget()
*/

QWidget * Q3WidgetStack::widget(int id) const
{
    return id != -1 ? dict->find(id) : 0;
}

/*!
    Returns the ID of the \a widget. Returns -1 if \a widget is 0 or
    is not being managed by this widget stack.

    \sa widget() addWidget()
*/

/*!
    Returns the currently visible widget (the one at the top of the
    stack), or 0 if nothing is currently being shown.

    \sa aboutToShow() id() raiseWidget()
*/

QWidget * Q3WidgetStack::visibleWidget() const
{
    return topWidget;
}

/*!
    \fn void Q3WidgetStack::aboutToShow(int id)

    This signal is emitted just before a managed widget is shown if
    that managed widget has an ID != -1. The \a id parameter is the numeric
    ID of the widget.

    If you call visibleWidget() in a slot connected to aboutToShow(),
    the widget it returns is the one that is currently visible, not
    the one that is about to be shown.
*/

/*!
    \fn void Q3WidgetStack::aboutToShow(QWidget *widget)

    \overload

    This signal is emitted just before a managed widget is shown. The
    argument is a pointer to the \a widget.

    If you call visibleWidget() in a slot connected to aboutToShow(),
    the widget returned is the one that is currently visible, not the
    one that is about to be shown.
*/

/*!
    \reimp
*/

void Q3WidgetStack::resizeEvent(QResizeEvent * e)
{
    Q3Frame::resizeEvent(e);
    setChildGeometries();
}

/*!
    \reimp
*/

QSize Q3WidgetStack::sizeHint() const
{
    constPolish();

    QSize size(0, 0);

    Q3IntDictIterator<QWidget> it(*dict);
    QWidget *w;

    while ((w = it.current()) != 0) {
        ++it;
        QSize sh = w->sizeHint();
        if (w->sizePolicy().horData() == QSizePolicy::Ignored)
            sh.rwidth() = 0;
        if (w->sizePolicy().verData() == QSizePolicy::Ignored)
            sh.rheight() = 0;
#ifndef QT_NO_LAYOUT
        size = size.expandedTo(sh).expandedTo(qSmartMinSize(w));
#endif
    }
    if (size.isNull())
        size = QSize(128, 64);
    size += QSize(2*frameWidth(), 2*frameWidth());
    return size;
}

/*!
    \reimp
*/
QSize Q3WidgetStack::minimumSizeHint() const
{
    constPolish();

    QSize size(0, 0);

    Q3IntDictIterator<QWidget> it(*dict);
    QWidget *w;

    while ((w = it.current()) != 0) {
        ++it;
        QSize sh = w->minimumSizeHint();
        if (w->sizePolicy().horData() == QSizePolicy::Ignored)
            sh.rwidth() = 0;
        if (w->sizePolicy().verData() == QSizePolicy::Ignored)
            sh.rheight() = 0;
#ifndef QT_NO_LAYOUT
        size = size.expandedTo(sh).expandedTo(w->minimumSize());
#endif
    }
    if (size.isNull())
        size = QSize(64, 32);
    size += QSize(2*frameWidth(), 2*frameWidth());
    return size;
}

/*!
    \reimp
*/
void Q3WidgetStack::childEvent(QChildEvent *e)
{
    if (e->child()->isWidgetType() && e->removed())
        removeWidget((QWidget *) e->child());
}

/*!
    \reimp
*/
bool Q3WidgetStack::event(QEvent* e)
{
    if (e->type() == QEvent::LayoutRequest || e->type() == QEvent::LayoutHint )
        updateGeometry(); // propgate layout hints to parent
    return Q3Frame::event(e);
}

QT_END_NAMESPACE


try
    {
        pTransaction = std::make_unique<Transaction>(Transaction::FromJSON(json));
    }
    catch (std::exception& e)
    {
        std::cout << "Failed to parse transaction." << std::endl;
        std::cout << e.what() << std::endl;
        return -1;
    }

#include <iostream>

#include <Consensus.h>
#include <Common/Util/FileUtil.h>
#include <Core/Global.h>
#include <Core/Context.h>
#include <Core/Models/Transaction.h>
#include <Core/Util/JsonUtil.h>
#include <Core/Validation/TransactionValidator.h>

#include "../../src/P2P/Messages/TransactionMessage.h"

int main(int argc, char* argv[])
{
    if (argc < 2)
    {
        std::cout << "Usage: tx_verifier <tx.json>" << std::endl;
        return -1;
    }

    auto pContext = Context::Create(Environment::MAINNET, Config::Default(Environment::MAINNET));
    Global::Init(pContext);

    std::vector<uint8_t> bytes;
    if (!FileUtil::ReadFile(argv[1], bytes)) {
        std::cout << "Failed to read json file at: " << argv[1] << std::endl;
        return -1;
    }

    std::string tx_json_str = std::string(bytes.cbegin(), bytes.cend());
    Json::Value json;
    if (!JsonUtil::Parse(tx_json_str, json)) {
        std::cout << "Failed to parse json" << std::endl;
        return -1;
    }

    std::unique_ptr<Transaction> pTransaction = nullptr;

    try
    {
        TransactionValidator().Validate(*pTransaction, (Consensus::HARD_FORK_INTERVAL * 4));
    }
    catch (std::exception& e)
    {
        std::cout << "Transaction validation failed." << std::endl;
        std::cout << e.what() << std::endl;
        return -1;
    }

    std::cout << "Transaction is valid" << std::endl;

    bytes = TransactionMessage(std::make_shared<Transaction>(*pTransaction)).Serialize(EProtocolVersion::V2);
    std::cout << HexUtil::ConvertToHex(bytes) << std::endl;

    std::cout << HexUtil::ConvertToHex(std::vector<uint8_t>{ bytes.begin() + 11, bytes.end() }) << std::endl;

    return 0;
}


switch (type) {
    case QtDebugMsg:
      level = "DEBUG";
      break;
    case QtWarningMsg:
      level = "WARN ";
      break;
    case QtCriticalMsg:
      level = "CRIT ";
      break;
    case QtFatalMsg:
      level = "FATAL";
      break;
    case QtInfoMsg:
      level = "INFO ";
      break;
  }

/**
 * Valeronoi is an app for generating WiFi signal strength maps
 *
 */

#include "log_helper.h"

#include <QDateTime>

namespace Valeronoi::util {

LogHelper &LogHelper::instance() {
  static LogHelper _instance;
  return _instance;
}

void LogHelper::log(const QString &msg) {
  if (!m_log_dialog) {
    m_buffer.append(msg);
  } else {
    m_log_dialog->log_message(msg);
  }
}

void LogHelper::set_log_dialog(Valeronoi::gui::dialog::LogDialog *log_dialog) {
  m_log_dialog = log_dialog;
  m_log_dialog->log_message(m_buffer);
  m_buffer.clear();
}

void log_handler(QtMsgType type, const QMessageLogContext &context,
                 const QString &msg) {
  (void)context;
  auto &helper = LogHelper::instance();
  QString level;

  const auto time = QDateTime::currentDateTime();
  helper.log("[ " + level + " ] " + time.toString("yyyy-MM-dd hh:mm:ss.zzz") +
             " " + msg);
}

}  // namespace Valeronoi::util


EthernetClient::operator bool() {
  return _sock != MAX_SOCK_NUM;
}

/**************************************************************************
	This code is part of the original Arduino Ethernet library with relevant
	license, has been modified for the integration with vNet drivers.

	All modification are tracked in the comments.
***************************************************************************/

// Select the Wiznet controller model
#if(ETH_W5100 || ETH_W5200)
#	include "frame/vNet/drivers/mcu_avr/ethW5x00/src/w5x00.h"
#elif(ETH_W5500)
#	include "frame/vNet/drivers/mcu_avr/ethW5x00/src/w5500.h"
#endif

#include "frame/vNet/drivers/mcu_avr/ethW5x00/src/socket.h"
#include "conf/eth/ethUsrCfg.h"

extern "C" {
  #include "string.h"
}

#include "Arduino.h"

#include "Ethernet.h"
#include "EthernetClient.h"
#include "EthernetServer.h"
#include "Dns.h"

uint16_t EthernetClient::_srcport = 1024;

EthernetClient::EthernetClient() : _sock(MAX_SOCK_NUM) {
}

EthernetClient::EthernetClient(uint8_t sock) : _sock(sock) {
}

int EthernetClient::connect(const char* host, uint16_t port) {
  // Look up the host first
  int ret = 0;
  DNSClient dns;
  IPAddress remote_addr;

  dns.begin(Ethernet.dnsServerIP());
  ret = dns.getHostByName(host, remote_addr);
  if (ret == 1) {
    return connect(remote_addr, port);
  } else {
    return ret;
  }
}

int EthernetClient::connect(IPAddress ip, uint16_t port) {
  if (_sock != MAX_SOCK_NUM)
    return 0;

  for (int sock = ST_SOCK; sock < MAX_SOCK_NUM; sock++) {		/***/
    uint8_t s = W5x00.readSnSR(sock);
    if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT || s == SnSR::CLOSE_WAIT) {
      _sock = sock;
      break;
    }
  }

  if (_sock == MAX_SOCK_NUM)
    return 0;

  _srcport++;
  if (_srcport == 0) _srcport = 1024;
  socket(_sock, SnMR::TCP, _srcport, 0);

  if (!::connect(_sock, rawIPAddress(ip), port)) {
    _sock = MAX_SOCK_NUM;
    return 0;
  }

  while (status() != SnSR::ESTABLISHED) {
    delay(1);
    if (status() == SnSR::CLOSED) {
      _sock = MAX_SOCK_NUM;
      return 0;
    }
  }

  return 1;
}

size_t EthernetClient::write(uint8_t b) {
  return write(&b, 1);
}

size_t EthernetClient::write(const uint8_t *buf, size_t size) {
  if (_sock == MAX_SOCK_NUM) {
    setWriteError();
    return 0;
  }
  if (!send(_sock, buf, size)) {
    setWriteError();
    return 0;
  }
  return size;
}

int EthernetClient::available() {
  if (_sock != MAX_SOCK_NUM)
    return W5x00.getRXReceivedSize(_sock);
  return 0;
}

int EthernetClient::read() {
  uint8_t b;
  if ( recv(_sock, &b, 1) > 0 )
  {
    // recv worked
    return b;
  }
  else
  {
    // No data available
    return -1;
  }
}

int EthernetClient::read(uint8_t *buf, size_t size) {
  return recv(_sock, buf, size);
}

int EthernetClient::peek() {
  uint8_t b;
  // Unlike recv, peek doesn't check to see if there's any data available, so we must
  if (!available())
    return -1;
  ::peek(_sock, &b);
  return b;
}

void EthernetClient::flush() {
  while (available())
    read();
}

void EthernetClient::stop() {
  if (_sock == MAX_SOCK_NUM)
    return;

  // attempt to close the connection gracefully (send a FIN to other side)
  disconnect(_sock);
  unsigned long start = millis();

  // wait a second for the connection to close
  while (status() != SnSR::CLOSED && millis() - start < 1000)
    delay(1);

  // if it hasn't closed, close it forcefully
  if (status() != SnSR::CLOSED)
    close(_sock);

  EthernetClass::_server_port[_sock] = 0;
  _sock = MAX_SOCK_NUM;
}

uint8_t EthernetClient::connected() {
  if (_sock == MAX_SOCK_NUM) return 0;

  uint8_t s = status();
  return !(s == SnSR::LISTEN || s == SnSR::CLOSED || s == SnSR::FIN_WAIT ||
    (s == SnSR::CLOSE_WAIT && !available()));
}

uint8_t EthernetClient::status() {
  if (_sock == MAX_SOCK_NUM) return SnSR::CLOSED;
  return W5x00.readSnSR(_sock);
}

// the next function allows us to use the client returned by
// EthernetServer::available() as the condition in an if-statement.

bool EthernetClient::operator==(const EthernetClient& rhs) {
  return _sock == rhs._sock && _sock != MAX_SOCK_NUM && rhs._sock != MAX_SOCK_NUM;
}