
/*!**************************************************************************

    module      : vkb431.cpp

    -------------------------------------------------------------------------

    author      : JuergenA
    responsible : UweH

    special area: Logging
    description : KB_CopyUpdBlob_interface

    last changed: 2001-03-08

    -------------------------------------------------------------------------

    copyright:    (c) 2001-2004 SAP AG


    ========== licence begin  GPL
    Copyright (c) 2001-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end




*****************************************************************************/

/*==========================================================================*
*  INCLUDES                                                                 *
*===========================================================================*/

#include "SAPDBCommon/SAPDB_Types.hpp"
#include "Logging/Log_ActionCopyUpdBlob.hpp"
#include "Logging/Log_ActionCreateDropFile.hpp"
#include "gsp00.h"
#include "ggg00.h"
#include "hbd01.h"
#include "hbd01_1.h" // b01niltree_id
#include "hbd05.h"
#include "ggg92.h"  // required for hkb50.h
#include "hkb50.h"
#include "hkb431.h" // check of PASCAL header vkb431

#include "gsp00_0.h" // ROUTINE_DBG_MSP00

#if COMPILEMODE_MSP00 >= SLOW_MSP00	
#include "hta99.h"
#include "hta01.h"
#endif


/*==========================================================================*
* LOCAL FUNCTIONS                                                           *
*===========================================================================*/

static void BuildAuxiliaryBlobId (const tgg00_TransContext &TransContext,
                                  tgg00_FileId             &AuxBlobId)
{
    AuxBlobId = b01niltree_id;
    
    AuxBlobId.fileType_gg00().clear();
    AuxBlobId.fileType_gg00().addElement (ftsByteStr_egg00);
    AuxBlobId.fileType_gg00().addElement (ftsConcurrent_egg00);
    
    AuxBlobId.fileTfn_gg00()     = tgg00_Tfn::fromConst (tfnAux_egg00);
    AuxBlobId.fileTransId_gg00() = TransContext.trWriteTransId_gg00;
    
    const SAPDB_Bool1 bPerm = SAPDB_TRUE;
    k50aux_fn_no (TransContext.trIndex_gg00, bPerm, AuxBlobId.fileAuxCnt_gg00());
}

//----------------------------------------------------------------------------

static void WriteBeforeImageUsingAuxBlob (tgg00_TransContext &TransContext,
                                          tgg00_FileId       &BlobId,
                                          SAPDB_Int4         BlobVersion,
                                          SAPDB_Int4         OffsetOverwriteArea,
                                          SAPDB_Int4         LengthOverwriteArea,
                                          SAPDB_Int4         LenTruncatedBlob)
{
    ROUTINE_DBG_MSP00 ("WriteBeforeImageUsingAuxBlob");
    
#if COMPILEMODE_MSP00 >= SLOW_MSP00
    BASIS_ERROR_TRACE (kb_log, TransContext.trError_gg00);

    t01treeid (kb_log, "BlobId      ", BlobId);
    t01p2int4 (kb_log, "BlobVersion ", BlobVersion
        ,              "OffOverwrite", OffsetOverwriteArea);
    t01p2int4 (kb_log, "LenOverwrite", LengthOverwriteArea
        ,              "LenTruncated", LenTruncatedBlob);
#endif

    // before image: copy old contents of destination blob to a before image file

    tgg00_FileId AuxBlobId;
    
    BuildAuxiliaryBlobId (TransContext, AuxBlobId);
    
    // create an action that will restore the overwritten image of the blob in case of undo
    // restoring is done by copying the original bytes from auxiliary blob to the blob
    
    Log_ActionCopyBlob BeforeImage 
        (
        AuxBlobId.fileName_gg00(), // Source
        BlobId.fileName_gg00(),    // Destin
        BlobVersion,               // DestinVersion
        LengthOverwriteArea,       // CopyLength
        0,                         // SourceOffset
        OffsetOverwriteArea,       // DestinOffset
        LenTruncatedBlob);
    
    // the before image entry has to be written before the auxiliary blob is created
    BeforeImage.WriteBeforeImage (TransContext);
    
    if (e_ok != TransContext.trError_gg00) return;
    
    // in case of rollback the auxiliary blob will be destoyed by BeforeImage.Execute
    // in case of commit   the auxiliary blob will be destoyed by PrefixDestoyFiles
    b01bcreate_bytestr (TransContext, AuxBlobId);
    
    if (e_ok != TransContext.trError_gg00) return;
    
    AuxBlobId.fileBdUse_gg00().clear();
    
    // copy the original bytes contained in the overwrite area of the blob to the auxiliary blob
    b05copy_bytestr (
        TransContext,
        BlobId,    OffsetOverwriteArea+1,
        AuxBlobId, 1,
        LengthOverwriteArea,
        BlobVersion);
}


/*==========================================================================*
* PASCAL INTERFACE                                                          *
*===========================================================================*/

externPascal void kb431CopyBlob (tgg00_TransContext &TransContext,
                                 tgg00_FileId       &SourceBlob,
                                 tgg00_FileId       &DestinBlob,
                                 tsp00_Int4         OldDestinVersion,
                                 tsp00_Int4         OldDestinLength,
                                 tsp00_Int4         SourceOffset,
                                 tsp00_Int4         DestinOffset,
                                 tsp00_Int4         CopyLength)
{
    ROUTINE_DBG_MSP00 ("kb431CopyBlob");
    
#if COMPILEMODE_MSP00 >= SLOW_MSP00
    BASIS_ERROR_TRACE (kb_log, TransContext.trError_gg00);

    t01treeid (kb_log, "SourceBlob  ", SourceBlob);
    t01treeid (kb_log, "DestinBlob  ", DestinBlob);
    t01p2int4 (kb_log, "OldDestVers ", OldDestinVersion
        ,              "SourceOffset", SourceOffset);
    t01p2int4 (kb_log, "OldDestLen  ", OldDestinLength
        ,              "DestinOffset", DestinOffset);
    t01int4   (kb_log, "CopyLength  ", CopyLength);
#endif

    SAPDB_Int4 NewDestinVersion =
        ((OldDestinVersion < SAPDB_MAX_INT4) && (OldDestinVersion > 0)) ? (OldDestinVersion + 1) : 1;
    
    SAPDB_Int4 LengthOverwriteArea =
        (DestinOffset + CopyLength <= OldDestinLength) ? CopyLength : (OldDestinLength - DestinOffset);
    
    if (LengthOverwriteArea > 0)
    {
        // before image: copy old contents of destination blob to an auxiliary blob        
        SAPDB_Int4 LenOldTruncatedBlob = (LengthOverwriteArea < CopyLength) ? OldDestinLength : 0;
        
        WriteBeforeImageUsingAuxBlob (TransContext, DestinBlob, OldDestinVersion,
            DestinOffset, LengthOverwriteArea, LenOldTruncatedBlob);
    }
    else
    {
        // before image: truncation of destination blob
        
        Log_ActionTruncateBlob
            BeforeImage (DestinBlob.fileName_gg00(), OldDestinVersion, OldDestinLength);
        
        BeforeImage.WriteBeforeImage (TransContext);
    }
    
    if (e_ok != TransContext.trError_gg00) return;
    
    if ( SourceBlob.fileTabId_gg00() != DestinBlob.fileTabId_gg00() )
    {
        Log_ActionCopyBlob AfterImage
            (
            SourceBlob.fileName_gg00(),
            DestinBlob.fileName_gg00(),
            NewDestinVersion,
            CopyLength,
            SourceOffset,
            DestinOffset,
            0);         // without any truncation (redo: DestinBlob may be expanded)
        
        AfterImage.ExecuteAction (TransContext, &SourceBlob, &DestinBlob);
        
        if (e_ok != TransContext.trError_gg00) return;
        
        AfterImage.WriteAfterImage (TransContext);
    }
    else
    {
        tgg00_FileId AuxBlobId;
        
        BuildAuxiliaryBlobId (TransContext, AuxBlobId);
        
        Log_ActionDropFile BeforeImageAuxBlobId (AuxBlobId.fileName_gg00());
        
        BeforeImageAuxBlobId.WriteBeforeImage (TransContext);
        
        if (e_ok != TransContext.trError_gg00) return;
        
        Log_ActionCopySameBlob AfterImage
            (
            DestinBlob.fileName_gg00(),
            AuxBlobId.fileName_gg00(),
            NewDestinVersion,
            CopyLength,
            SourceOffset,
            DestinOffset);
        
        AfterImage.ExecuteAction (TransContext, DestinBlob, AuxBlobId);
        
        if (e_ok != TransContext.trError_gg00) return;
        
        AfterImage.WriteAfterImage (TransContext);
    }
}

//----------------------------------------------------------------------------

externPascal void kb431ExpandBlob (tgg00_TransContext &TransContext,
                                   tgg00_FileId       &Blob,
                                   tsp00_Int4         BlobVersion,
                                   tsp00_Int4         OldBlobLength,
                                   tsp00_Int4         NewExpandedBlobLen,
                                   tsp00_Byte         ExpandByte)
{    
    ROUTINE_DBG_MSP00 ("kb431ExpandBlob");
    
#if COMPILEMODE_MSP00 >= SLOW_MSP00
    BASIS_ERROR_TRACE (kb_log, TransContext.trError_gg00);

    t01treeid (kb_log, "Blob        ", Blob);
    t01p2int4 (kb_log, "BlobVersion ", BlobVersion
        ,              "OldBlobLen  ", OldBlobLength);
    t01p2int4 (kb_log, "NewExpandLen", NewExpandedBlobLen
        ,              "ExpandByte  ", ExpandByte);
#endif

    if (OldBlobLength == NewExpandedBlobLen) return;
    
    Log_ActionTruncateBlob BeforeImage (Blob.fileName_gg00(), BlobVersion, OldBlobLength);
    
    Log_ActionExpandBlob   AfterImage  (Blob.fileName_gg00(), NewExpandedBlobLen, ExpandByte);
    
    BeforeImage.WriteBeforeImage (TransContext);
    
    if (e_ok != TransContext.trError_gg00) return;
    
    AfterImage.ExecuteAction (TransContext, &Blob); 
    
    if (e_ok != TransContext.trError_gg00) return;
    
    AfterImage.WriteAfterImage (TransContext);
}

//----------------------------------------------------------------------------

externPascal void kb431TruncateBlob (tgg00_TransContext &TransContext,
                                     tgg00_FileId       &Blob,
                                     tsp00_Int4         BlobVersion,
                                     tsp00_Int4         OldBlobLength,
                                     tsp00_Int4         NewTruncatedBlobLen)
{    
    ROUTINE_DBG_MSP00 ("kb431TruncateBlob");
    
#if COMPILEMODE_MSP00 >= SLOW_MSP00
    BASIS_ERROR_TRACE (kb_log, TransContext.trError_gg00);

    t01treeid (kb_log, "Blob        ", Blob);
    t01int4   (kb_log, "BlobVersion ", BlobVersion);
    t01p2int4 (kb_log, "OldBlobLen  ", OldBlobLength
        ,              "NewTruncated", NewTruncatedBlobLen);
#endif

    if (OldBlobLength == NewTruncatedBlobLen) return;
    
    WriteBeforeImageUsingAuxBlob (TransContext, Blob, BlobVersion,
        NewTruncatedBlobLen,                 // OffsetOverwriteArea
        OldBlobLength - NewTruncatedBlobLen, // LengthOverwriteArea
        0);                                  // without any truncation (undo: the blob is expanded)
    
    if (e_ok != TransContext.trError_gg00) return;
    
    Log_ActionTruncateBlob AfterImage (Blob.fileName_gg00(), BlobVersion, NewTruncatedBlobLen);
    
    AfterImage.ExecuteAction (TransContext, &Blob); 
    
    if (e_ok != TransContext.trError_gg00) return;
    
    AfterImage.WriteAfterImage (TransContext);
}

//----------------------------------------------------------------------------

externPascal void kb431UpdateBlob (tgg00_TransContext &TransContext,
                                   tgg00_FileId       &Blob,
                                   tsp00_Int4         BlobVersion,
                                   tsp00_Int4         OldBlobLength,
                                   tsp00_Int4         InsertOffset,
                                   tsp00_MoveObjPtr   pBuf,
                                   tsp00_Int4         BufOffset,
                                   tsp00_Int4         BufLength)
{
    ROUTINE_DBG_MSP00 ("kb431UpdateBlob");
    
#if COMPILEMODE_MSP00 >= SLOW_MSP00
    BASIS_ERROR_TRACE (kb_log, TransContext.trError_gg00);

    t01treeid  (kb_log, "Blob        ", Blob);
    t01int4    (kb_log, "BlobVersion ", BlobVersion);
    t01p2int4  (kb_log, "OldBlobLen  ", OldBlobLength
        ,               "InsertOffset", InsertOffset);
    t01p2int4  (kb_log, "BufOffset   ", BufOffset
        ,               "BufLength   ", BufLength);
    t01moveobj (kb_log, pBuf, BufOffset+1, BufOffset+BufLength);
#endif

    if (BufLength <= 0) return;
    
    SAPDB_Int4 LengthOverwriteArea =
        (InsertOffset + BufLength <= OldBlobLength) ? BufLength : (OldBlobLength - InsertOffset);
    
    if (LengthOverwriteArea > 0)
    {
        // before image: copy old contents of blob to an auxiliary blob 
        
        SAPDB_Int4 LenOldTruncatedBlob =
            (InsertOffset + BufLength <= OldBlobLength) ? 0 : OldBlobLength;
        
        WriteBeforeImageUsingAuxBlob (TransContext, Blob, BlobVersion,
            InsertOffset, LengthOverwriteArea, LenOldTruncatedBlob);
    }
    else
    {
        // before image: truncation of destination blob
        
        Log_ActionTruncateBlob BeforeImage (Blob.fileName_gg00(), BlobVersion, OldBlobLength);
        
        BeforeImage.WriteBeforeImage (TransContext);
    }
    
    if (e_ok != TransContext.trError_gg00) return;
    
    Log_ActionUpdateBlob AfterImage (Blob.fileName_gg00(), InsertOffset,
        (REINTERPRET_CAST (SAPDB_Byte*, pBuf))+BufOffset, BufLength);
    
    AfterImage.ExecuteAction (TransContext, &Blob); 
    
    if (e_ok != TransContext.trError_gg00) return;
    
    AfterImage.WriteAfterImage (TransContext);
}

/*===========================================================================*
*  END OF CODE                                                               *
*============================================================================*/
