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

    module      : Log_CommandInsDelUpd.hpp

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

    author      : JuergenA
    responsible : UweH

    special area: Logging
    description : defines classes to handle the insert, delete and update commands

    last changed: 2001-04-12

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

    copyright:    (c) 2000-2004 SAP AG


    ========== licence begin  GPL
    Copyright (c) 2000-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




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


#ifndef LOG_COMMAND_INS_DEL_UPD_H
#define LOG_COMMAND_INS_DEL_UPD_H

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

#include "SAPDBCommon/MemoryManagement/SAPDBMem_IRawAllocator.hpp"
#include "Logging/Log_Types.hpp"
#include "Logging/Log_ActionInsDelRec.hpp"
#include "Logging/Log_ActionUpdateRec.hpp"
#include "Logging/Log_InvDescMap.hpp"
#include "Logging/Log_ReadWriteActionImage.hpp"

#include "ggg00.h"


/*===========================================================================*
*  CLASSES, STRUCTURES, TYPES, UNIONS ...                                    *
*============================================================================*/

//===================================================================================
/*! class:       Log_InvHandling

    description: index handling
*/
class Log_InvHandling
{
private:
    
    const tgg00_FileId *m_pPrimFileId;
    const tgg00_Rec    *m_pOldRec;
    const tgg00_Rec    *m_pNewRec;

    Log_InvDescMap      m_InvDescMap;
    bool                m_bDelInvPostponed;

protected:
    
    //--------------------------------------------------------------Log_InvHandling---
    /*  function:    GetFilename
    */
    const tgg00_Filename &GetFilename () const
    {
        return ( m_pPrimFileId->fileName_gg00() );
    }
    
    //--------------------------------------------------------------Log_InvHandling---
    /*  function:    GetInvDescMap
    */
    const Log_InvDescMap *GetInvDescMap () const
    {
        return ( &m_InvDescMap );
    }

    //--------------------------------------------------------------Log_InvHandling---
    /*  function:    GetWriteAccessInvDescMap
    */
    Log_InvDescMap *GetWriteAccessInvDescMap ()
    {
        return ( &m_InvDescMap );
    }
    
    //--------------------------------------------------------------Log_InvHandling---
    /*  function:    GetOldRec
    */
    const tgg00_Rec *GetOldRec () const
    {
        return (m_pOldRec);
    }
    
    //--------------------------------------------------------------Log_InvHandling---
    /*  function:    GetNewRec
    */
    const tgg00_Rec *GetNewRec () const
    {
        return (m_pNewRec);
    }
    
    //--------------------------------------------------------------Log_InvHandling---
    /*  function:    InitAfterImage
    */
    inline void InitAfterImage (
        const tgg00_FileId &PrimFileId,
        const tgg00_Rec    *pNewRec);
    
    //--------------------------------------------------------------Log_InvHandling---
    /*  function:    InitBeforeImage
    */
    inline void InitBeforeImage (
        const tgg00_FileId &PrimFileId,
        const tgg00_Rec    *pOldRec);
    
    //--------------------------------------------------------------Log_InvHandling---
    /*  function:    InitBeforeImageRecord
    */
    inline void InitBeforeImageRecord (const tgg00_Rec    *pOldRec)
    {
        this->m_pOldRec = pOldRec;
    }

public:

    //--------------------------------------------------------------Log_InvHandling---
    /*! function:    Log_InvHandling ctor
    
        description: empty inv description map
    */
    inline Log_InvHandling ();
    
    //--------------------------------------------------------------Log_InvHandling---
    /*! function:    AssignInvDescMap
    
        description: assigns an existing StackDesc to the inv description map 
       
        arguments:   StackDesc [in]
    */
    inline void AssignInvDescMap (const tgg00_StackDesc &StackDesc);
    
    //--------------------------------------------------------------Log_InvHandling---
    /*! function:    AddInv
    
        description: inserts all secondary keys of the after image into the inv trees

        arguments:   TransContext [in out]
    */
    void AddInv (tgg00_TransContext &TransContext) const;

    //--------------------------------------------------------------Log_InvHandling---
    /*! function:    CheckUniqueIndex
    
        description: unique check of all secondary keys execept those marked to be checked later

                     The check requires an initialized after image.
      
        arguments:   TransContext [in out]
    */
    void CheckUniqueIndex (tgg00_TransContext &TransContext) const;

    //--------------------------------------------------------------Log_InvHandling---
    /*! function:     ContainsLateUniqueCheck
    
        return value: true, if InvDescMap contains an index which has to be checked later
    */
    bool ContainsLateUniqueCheck () const
    {
        return ( m_InvDescMap.ContainsLateUniqueCheck() );
    }

    //--------------------------------------------------------------Log_InvHandling---
    /*! function:     ContainsUniqueIndex
    
        return value: true, if InvDescMap contains an unique index
    */
    bool ContainsUniqueIndex () const
    {
        return ( m_InvDescMap.ContainsUniqueIndex() );
    }
    
    //--------------------------------------------------------------Log_InvHandling---
    /*! function:    DelInv
    
        description: deletes all secondary keys of the before image from the inv trees

        arguments:   TransContext [in out]
    */
    void DelInv (tgg00_TransContext &TransContext) const;
   
    //--------------------------------------------------------------Log_InvHandling---
    /*! function:     ExecuteOutsideBd

        description:  Sets the internal state, that DelInv has to be called outside any BD-function 
    
        return value: true, if DelInv has to be called outside any BD-function 
    */
    inline bool ExecuteOutsideBd ();

    //--------------------------------------------------------------Log_InvHandling---
    /*! function:     ExistsAnyIndex
    
        return value: true, if InvDescMap contains any index
    */
    bool ExistsAnyIndex () const
    {
        return ( ! m_InvDescMap.IsEmpty() );
    }

    //--------------------------------------------------------------Log_InvHandling---
    /*! function:     IsExecutionPostponed
    
        return value: true, if DelInv has to be called outside any BD-function 
    */
    bool IsExecutionPostponed () const
    {
        return (m_bDelInvPostponed);
    }

    //--------------------------------------------------------------Log_InvHandling---
    /*! function:    LockAndCheckUniqueIndex
    
        description: locks all unique secondary keys in exclusive mode and performes a unique check

                     The check requires an initialized after image. Keys are not checked,
                     if they are marked to be checked later.

                     The keys of the before and after images are locked,
                     if both images are initialized.

        arguments:   TransContext [in out] 
                     GrantedMode  [out]
    */
    void LockAndCheckUniqueIndex (
        tgg00_TransContext  &TransContext,
        tgg00_LockReqMode   &GrantedMode) const;
    
    //--------------------------------------------------------------Log_InvHandling---
    /*! function:    LockUniqueIndex
    
        description: locks all unique secondary keys of the initialized images in exclusive mode

        arguments:   TransContext    [in out]
                     GrantedMode     [out]
                     BeforeImageOnly [in] may be omitted (default == false)
    */
    void LockUniqueIndex (
        tgg00_TransContext  &TransContext,
        tgg00_LockReqMode   &GrantedMode,
        bool                 BeforeImageOnly = false) const;
    
};
/*! endclass: Log_InvHandling */


//===================================================================================
/*! class:       Log_DeleteCmd

    description: handling of the delete command
*/
class Log_DeleteCmd: public Log_InvHandling
{
private:
    
    Log_ActionInsDelRec  m_BeforeImage;
    Log_ActionInsDelRec  m_AfterImage;
    
public:
    
    //--------------------------------------------------------------Log_DeleteCmd---
    /*! function:    Log_DeleteCmd ctor
    
        description: empty Log_DeleteCmd
    */
    inline Log_DeleteCmd ();
    
    //--------------------------------------------------------------Log_DeleteCmd---
    /*! function:    Init
    
        description: initializes the before and after image

       
        arguments:   PrimFileId [in] 
                     pOldRec    [in] pointer to the old record
    */
    inline void Init (
        const tgg00_FileId &PrimFileId,
        const tgg00_Rec    *pOldRec);

    //--------------------------------------------------------------Log_DeleteCmd---
    /*! function:    PostponedExecution
    
        description: writes the before image, deletes all secondary keys and the record

        arguments:   TransContext [in out]
                     PrimFileId   [in out]
    */
    void PostponedExecution (
        tgg00_TransContext &TransContext,
        tgg00_FileId       &PrimFileId) const;
    
    //--------------------------------------------------------------Log_DeleteCmd---
    /*! function:    WriteAfterImage
    
        description: writes the after image
       
        arguments:   TransContext [in out]
    */
    inline void WriteAfterImage (tgg00_TransContext &TransContext) const
    {
        m_AfterImage.WriteAfterImage (TransContext);
    }

    //--------------------------------------------------------------Log_DeleteCmd---
    /*! function:    WriteBeforeImage
    
        description: writes the before image
       
        arguments:   TransContext [in out]
    */
    void WriteBeforeImage (tgg00_TransContext &TransContext) const
    {
        m_BeforeImage.WriteBeforeImage (TransContext);
    }

};
/*! endclass: Log_DeleteCmd */


//===================================================================================
/*! class:       Log_InsertCmd

    description: handling of the insert command
*/
class Log_InsertCmd: public Log_InvHandling
{ 
private:

    Log_ActionInsDelRec  m_BeforeImage;
    Log_ActionInsDelRec  m_AfterImage;
    
public:

    //--------------------------------------------------------------Log_InsertCmd---
    /*! function:    Log_InsertCmd ctor
    
        description: empty Log_InsertCmd
    */
    inline Log_InsertCmd ();

    //--------------------------------------------------------------Log_InsertCmd---
    /*! function:    Init
    
        description: initializes the before and after image

       
        arguments:   PrimFileId [in] 
                     pNewRec    [in] pointer to the new record
    */
    inline void Init (
        const tgg00_FileId &PrimFileId,
        const tgg00_Rec    *pNewRec);

    //--------------------------------------------------------------Log_InsertCmd---
    /*! function:    WriteAfterImage
    
        description: writes the after image
       
        arguments:   TransContext [in out]
    */
    inline void WriteAfterImage (tgg00_TransContext &TransContext) const
    {
        m_AfterImage.WriteAfterImage (TransContext);
    }

    //--------------------------------------------------------------Log_InsertCmd---
    /*! function:    WriteBeforeImage
    
        description: writes the before image
       
        arguments:   TransContext [in out]
    */
    void WriteBeforeImage (tgg00_TransContext &TransContext) const
    {
        m_BeforeImage.WriteBeforeImage (TransContext);
    }

};
/*! endclass: Log_InsertCmd */


//===================================================================================
/*! class:       Log_UpdateCmd

    description: handling of the delete command
*/
class Log_UpdateCmd: public Log_InvHandling
{
private:

    Log_ActionUpdateRec  m_BeforeImage;
    Log_ActionUpdateRec  m_AfterImage;
    
public:

    //--------------------------------------------------------------Log_UpdateCmd---
    /*! function:    Log_UpdateCmd ctor
    
        description: empty Log_UpdateCmd
    */
    inline Log_UpdateCmd ();

    //--------------------------------------------------------------Log_UpdateCmd---
    /*! function:    AllocateColumnMap
    
        description: allocates all column entries for further calls of InsertColumn
        
        arguments:   RawAllocator [ref]
                     MaxEntries   [in]
                     IsOk         [out]
    */
    inline void AllocateColumnMap (
        SAPDBMem_IRawAllocator &RawAllocator,
        SAPDB_Int4              MaxEntries,
        bool                   &IsOk);
    
    //--------------------------------------------------------------Log_UpdateCmd---
    /*! function:    CreateNewRec
    
        description: initializes the before and after image
       
        arguments:   RawAllocator [ref]
                     PrimFileId   [in] 
                     pOldRecord   [in]  pointer to the existing record
                     pNewRecord   [out] pointer to the new record
                     Error        [out]
    */
    void CreateNewRec (
        SAPDBMem_IRawAllocator &RawAllocator,                                            
        const tgg00_FileId     &PrimFileId,
        const tgg00_Rec        *pOldRecord,
        tgg00_Rec              *pNewRecord,
        SAPDB_Int4              NewRecSize,
        tgg00_BasisError       &Error);
    
    //--------------------------------------------------------------Log_UpdateCmd---
    /*! function:    ExistsEntry

        return result: true, if the entry exists in the record column map of the after image

        arguments:   StackEntry [in]
    */
    bool ExistsEntry (const tgg00_StackEntry &StackEntry) const
    {
        return ( m_AfterImage.ExistsEntry (StackEntry) );
    }

    //--------------------------------------------------------------Log_ActionUpdateRec---
    /*! function:    InitAfterImageWithExistingNewRec
    
        description: initializes the after image using an existing new record.
        
        arguments:   PrimFileId [in]
                     pNewRecord [in]  pointer to the old record
    */
    void InitAfterImageWithExistingNewRec (
        const tgg00_FileId &PrimFileId,
        const tgg00_Rec    *pNewRecord)
    {    
        Log_InvHandling::InitAfterImage (PrimFileId, pNewRecord);
    }

    //--------------------------------------------------------------Log_ActionUpdateRec---
    /*! function:    InitBeforeImageForExistingNewRec
    
        description: initializes the before image. The after image has to be initialized already.
        
        arguments:   RawAllocator [ref]
                     pOldRecord   [in]  pointer to the old record
                     Error        [out]
    */
    inline void InitBeforeImageForExistingNewRec (
        SAPDBMem_IRawAllocator &RawAllocator,
        const tgg00_Rec        *pOldRecord,
        tgg00_BasisError       &Error);

    //--------------------------------------------------------------Log_UpdateCmd---
    /*! function:    InsertColumn
    
        description: inserts a column description with its value

        arguments:   StackEntry  [in]  description of the record column
                     pValue      [in]  pointer to the value
                     ValueLength [in]  the length of the value
                     Error       [out]
    */
    void InsertColumn (
        const tgg00_StackEntry &StackEntry,
        const SAPDB_Byte       *pValue,
        SAPDB_Int4              ValueLength,
        tgg00_BasisError       &Error)
    {
        m_AfterImage.InsertColumn (StackEntry, pValue, ValueLength, Error);
    }

    //--------------------------------------------------------------Log_UpdateCmd---
    /*! function:    PostponedExecution
    
        description: writes the before image, deletes all secondary keys and replaces the record

        arguments:   TransContext [in out]
                     PrimFileId   [in out]
    */
    void PostponedExecution (
        tgg00_TransContext &TransContext,
        tgg00_FileId       &PrimFileId) const;

    //--------------------------------------------------------------Log_UpdateCmd---
    /*! function:    WriteAfterImage
    
        description: writes the after image
       
        arguments:   TransContext [in out]
    */
    void WriteAfterImage (tgg00_TransContext &TransContext) const
    {
        m_AfterImage.WriteAfterImage (TransContext);
    }

    //--------------------------------------------------------------Log_UpdateCmd---
    /*! function:    WriteBeforeImage
    
        description: writes the before image
       
        arguments:   TransContext [in out]
    */
    void WriteBeforeImage (tgg00_TransContext &TransContext) const
    {    
        m_BeforeImage.WriteBeforeImage (TransContext);
    }

};
/*! endclass: Log_UpdateCmd */


/*==========================================================================*
*  DEFINITION OF INLINE METHODS                                             *
*==========================================================================*/

inline Log_InvHandling::Log_InvHandling ():

m_pPrimFileId      (NULL),
m_pOldRec          (NULL),
m_pNewRec          (NULL),
m_InvDescMap       (),
m_bDelInvPostponed (false)
{ }

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

inline void Log_InvHandling::InitAfterImage (const tgg00_FileId &PrimFileId,
                                             const tgg00_Rec    *pNewRec)
{
    this->m_pPrimFileId = &PrimFileId;
    this->m_pNewRec     = pNewRec;
}

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

inline void Log_InvHandling::InitBeforeImage (const tgg00_FileId &PrimFileId,
                                              const tgg00_Rec    *pOldRec)
{
    this->m_pPrimFileId = &PrimFileId;
    this->m_pOldRec     = pOldRec;
}

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

inline void Log_InvHandling::AssignInvDescMap (const tgg00_StackDesc &StackDesc)
{
    if (StackDesc.mmult_cnt <= 0)  return;
    
    this->m_InvDescMap.Assign (
        &((*StackDesc.mst_addr())[StackDesc.mmult_pos-1]),
        StackDesc.mmult_cnt, 
        true); // LookForUniqueEntries
}

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

inline bool Log_InvHandling::ExecuteOutsideBd ()
{
    if ( this->m_InvDescMap.IsEmpty() ) return (false);
    
    this->m_bDelInvPostponed = true;
    return (true);
}

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

inline Log_DeleteCmd::Log_DeleteCmd ():

Log_InvHandling (),
m_BeforeImage   (Log_DeleteRecord, true),
m_AfterImage    (Log_DeleteRecord, false)
{ }

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

inline void Log_DeleteCmd::Init (const tgg00_FileId &PrimFileId,
                                 const tgg00_Rec    *pOldRec)
{
    Log_InvHandling::InitBeforeImage (PrimFileId, pOldRec);
    
    this->m_BeforeImage.Init (PrimFileId.fileName_gg00(), pOldRec, Log_InvHandling::GetInvDescMap());
    
    this->m_AfterImage.Init
        (PrimFileId.fileName_gg00(), &(pOldRec->recKey_gg00()), Log_InvHandling::GetInvDescMap());
}

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

inline Log_InsertCmd::Log_InsertCmd ():

Log_InvHandling (),
m_BeforeImage   (Log_InsertRecord, true),
m_AfterImage    (Log_InsertRecord, false)
{ }

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

inline void Log_InsertCmd::Init (const tgg00_FileId &PrimFileId,
                                 const tgg00_Rec    *pNewRec)
{
    Log_InvHandling::InitAfterImage (PrimFileId, pNewRec);

    this->m_BeforeImage.Init
        (PrimFileId.fileName_gg00(), &(pNewRec->recKey_gg00()), Log_InvHandling::GetInvDescMap());
    
    this->m_AfterImage.Init  (PrimFileId.fileName_gg00(), pNewRec, Log_InvHandling::GetInvDescMap());
}

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

inline Log_UpdateCmd::Log_UpdateCmd ():

Log_InvHandling (),
m_BeforeImage   (),
m_AfterImage    ()
{ }

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

inline void Log_UpdateCmd::AllocateColumnMap (SAPDBMem_IRawAllocator &RawAllocator,
                                              SAPDB_Int4              MaxEntries,
                                              bool                   &IsOk)
{
    IsOk = true;
    
    this->m_AfterImage.AllocateColumnMap (RawAllocator, MaxEntries, IsOk);
    
    if ( ! IsOk ) return;
    
    this->m_BeforeImage.AllocateColumnMap (RawAllocator, MaxEntries, IsOk);
}

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

inline void Log_UpdateCmd::InitBeforeImageForExistingNewRec (SAPDBMem_IRawAllocator &RawAllocator,
                                                             const tgg00_Rec        *pOldRecord,
                                                             tgg00_BasisError       &Error)
{    
    if (e_ok != Error) return;
    
    Log_InvHandling::InitBeforeImageRecord (pOldRecord);
    
    this->m_AfterImage.InitAfterBeforeImageWithExistingNewRec (
        RawAllocator,
        Log_InvHandling::GetFilename(),
        Log_InvHandling::GetInvDescMap(),
        pOldRecord,
        Log_InvHandling::GetNewRec(),
        this->m_BeforeImage,
        Error);
}

#endif  /* LOG_COMMAND_INS_DEL_UPD_H */
