/*!
 * \file    OMS_Context.hpp
 * \author  IvanS, MarkusSi, PeterG, ThomasA
 * \brief   OMS context.
 */
/*

    ========== licence begin  GPL
    Copyright (c) 2002-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 __OMS_CONTEXT_HPP
#define __OMS_CONTEXT_HPP

#include "Oms/OMS_ContextDef.hpp"
#include "Oms/OMS_ClassIdHash.hpp"
#include "Oms/OMS_SessionDef.hpp"
#include "Oms/OMS_GuidEntry.hpp"
#include "Oms/OMS_VarObjInfo.hpp"
#include "Oms/OMS_UnknownContainerId.hpp"
#include "Oms/OMS_HResult.hpp"
#include "Oms/OMS_Exceptions.hpp"
#include "Oms/OMS_ClassIdEntry.hpp"
#include "Oms/OMS_CacheMissEntry.hpp"
#include "Oms/OMS_VarOid.hpp"
#include "SAPDBCommon/SAPDB_MemCopyMove.hpp"


inline void OMS_Context::AssignLcSink(IliveCacheSink* pSink) 
{
  m_currLcSink = pSink; 
  //m_sysLcSink  = OMS_Globals::GetCurrentLcSink();
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::CheckDBError(tsp00_Int2 e, const char* msg, const OmsObjectId& oid) 
{
  if (0 != e) {
    m_session->ThrowDBError (e, msg, oid, __MY_FILE__, __LINE__);
  }
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::CheckCompatibility(const ClassIDRef guid, OmsObjectContainerPtr pObj) 
{
  if (NULL == pObj) {
    return;
  }
  if (!omsIsCompatibleGuid(pObj->GetContainerInfo(this)->GetGuid(), guid)) {
    OMS_ClassIdEntry* pContainerInfo = pObj->GetContainerInfo(this);
    if (NULL != pContainerInfo) {
      if (pContainerInfo->IsDerivedClassOf(guid)) {
        return;
      }
    }
    // OMS_GuidEntry* pClassInfo = GetClassInfo(guid); // TODO: use for knldiag message
    m_session->ThrowDBError (e_object_not_found, "OMS_Context::CheckCompatibility", pObj->m_oid, __MY_FILE__, __LINE__);
  }
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::CheckIfContainerNotDropped(OMS_ClassIdEntry* pContainerInfo) 
{
  m_containerDir.CheckIfNotDropped(pContainerInfo);
}

/*----------------------------------------------------------------------*/

inline bool OMS_Context::CheckOid (const OmsObjectId& oid, const ClassIDRef guid) 
{
  const char msg[] = "OMS_Context::CheckOid";

  if (oid) {
    OMS_ClassIdEntry* pContainerInfo = NULL;
    OmsObjectContainer *pObj = FindObjInContext (&oid, /*ignoreGeneration=*/false);
    if (NULL != pObj) {
      // Object exits already in the liboms-cache
      if (pObj->DeletedFlag()) {
        // Object is marked as deleted
        return false;
      } 

      pContainerInfo = pObj->GetContainerInfoNoCheck(this);
    }
    else {
      // Object does not exist in the liboms-cache. 

      if ((!IsVersion() || !IsUnloaded()) && (OMS_VERSION_OBJ_PAGE_NO == oid.getPno())){
        // Oid corresponds to an object which has been created in a version. As either no version is
        // active or version is not unloaded the object must have been found in the liboms-cache
        // if it exists.
        return false;
      }

      m_session->m_currVarObjChunk.Clear();
      m_session->m_currVarObjChunk.m_seq.gg91SetNilRef();  

      // Try to read object from the kernel.
      int              objLen;
      int              objHistReadCount;
      tgg00_BasisError DBError;
      OMS_UnknownContainerId FileId;
      OMS_HResult hr = m_currLcSink->GetObj (
        m_consistentView,
        FileId,
        m_pVersionContext,
        *REINTERPRET_CAST(OmsTypeOid*, CONST_CAST(OmsObjectId*, &oid)),
        false,  // doLock  
        m_session->m_currVarObjChunk.m_seq,
        sizeof(m_session->m_currVarObjChunk.m_container), 
        ((unsigned char*) &m_session->m_currVarObjChunk.m_container), 
        objLen,
        objHistReadCount,
        DBError);

      if (0 == DBError) {
        // Object was found in the kernel
        m_session->IncLogHop(objHistReadCount);

        if (FileId.IsVarObjFile()) {
          // Specified oid corresponds to a var-object although a normal object is expected
          return false;
        }
        else {
          pContainerInfo = GetContainerInfo(FileId.GetContainerHandle());
          pObj = m_session->GetMemory (*pContainerInfo);
          SAPDB_MemCopyNoCheck (REINTERPRET_CAST(unsigned char*, &pObj->m_pobj) + sizeof(void*), &m_session->m_currVarObjChunk.m_container,
            pContainerInfo->GetPersistentSize());
          pObj->m_oid    = oid;
          pObj->m_objseq = m_session->m_currVarObjChunk.m_seq;
          PutObjectIntoContext(pObj, FileId.GetContainerHandle());
        }
      }
      else {
        // transform basis error into sql return code
        tsp00_Int2  SqlError;
        tsp00_Int4  len = sizeof(DBError);
        m_session->m_lcSink->MultiPurpose (m_change, mm_nil, &len, (unsigned char*) &DBError, &SqlError);

        if (SqlError != -102){
          return false;
        }
        else {
          throw DbpError (DbpError::DB_ERROR, SqlError, msg, oid, __MY_FILE__, __LINE__);
          return false;
        }
      }
    }

    // Check whether container is dropped
    if (pContainerInfo->GetContainerInfoPtr()->IsDropped()){
      return false;
    }

    // Check whether given guid is compatible with the guid of the object.
    const OMS_ClassInfo *pClassInfo = pContainerInfo->GetContainerInfoPtr()->GetClassInfoPtr();
    if (  !omsIsCompatibleGuid(pClassInfo->GetGuid(), guid)
      && !pClassInfo->IsDerivedClassOf(guid)) {
        return false;
      }
  }

  return true;
}

/*----------------------------------------------------------------------*/

inline bool OMS_Context::CheckOid (const OmsVarOid& oid)
{
  const char msg[] = "OMS_Context::CheckOid (VAR)";

  if (oid) {
    OMS_ClassIdEntry* pContainerInfo = NULL;
    OmsObjectContainer *pObj = FindObjInContext (&oid, /*ignoreGeneration=*/false);
    if (NULL != pObj) {
      // Object exists in the OMS-cache
      if (pObj->DeletedFlag()) {
        return false;
      } 

      pContainerInfo = pObj->GetContainerInfoNoCheck(this);
    }
    else {
      // Object does not exist in the OMS-Cache

      if ((!IsVersion() || !IsUnloaded()) && (OMS_VERSION_OBJ_PAGE_NO == oid.getPno())){
        // Oid corresponds to an object which has been created in a version. As either no version is
        // active or version is not unloaded the object must have been found in the liboms-cache
        // if it exists.
        return false;
      }

      m_session->m_currVarObjChunk.Clear();
      m_session->m_currVarObjChunk.m_seq.gg91SetNilRef(); 

      int              objLen;
      int              objHistReadCount;
      tgg00_BasisError DBError;
      OMS_UnknownContainerId FileId;
      OMS_HResult hr = m_currLcSink->GetObj (
        m_consistentView,
        FileId,
        m_pVersionContext,
        *REINTERPRET_CAST(OmsTypeOid*, CONST_CAST(OmsVarOid*, &oid)),
        false,  // doLock  
        m_session->m_currVarObjChunk.m_seq,
        sizeof(m_session->m_currVarObjChunk.m_container), 
        ((unsigned char*) &m_session->m_currVarObjChunk.m_container), 
        objLen,
        objHistReadCount,
        DBError);

      if (0 == DBError) {
        if (!FileId.IsVarObjFile()) {
          // Specified oid corresponds to a normal object although a var-object is expected
          return false;
        }
        else {
          pContainerInfo = GetContainerInfo(FileId.GetContainerHandle());
          m_session->m_currVarObjChunk.m_containerHandle = FileId.GetContainerHandle();
          if (objLen <= VAR_OBJ_CHUNK_SIZE) {
            m_session->m_currVarObjChunk.m_container.m_vobjSize = objLen;
          }
          pObj = LoadVarObject (*REINTERPRET_CAST(const OmsVarOid*, &oid), VarObjNoLock, 
            m_session->m_currVarObjChunk.m_container.m_vobjSize, m_session->m_currVarObjChunk, NULL);
        }
      }
      else {
        // transform basis error into sql return code
        tsp00_Int2  SqlError;
        tsp00_Int4  len = sizeof(DBError);
        m_session->m_lcSink->MultiPurpose (m_change, mm_nil, &len, (unsigned char*) &DBError, &SqlError);

        if (SqlError != -102) {
          return false;
        }
        else {
          throw DbpError (DbpError::DB_ERROR, SqlError, msg, oid, __MY_FILE__, __LINE__);
          return false;
        }
      }
    }

    // Check whether container is dropped
    if (pContainerInfo->GetContainerInfoPtr()->IsDropped()){
      return false;
    }

    // Check whether the object is a var-object
    if (!pContainerInfo->GetContainerInfoPtr()->GetClassInfoPtr()->IsVarObject()) {
      return false;
    }
  }

  return true;  
}

/*----------------------------------------------------------------------*/

inline void  OMS_Context::ClearObjCache() 
{
  m_oidDir.Clear();
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::CloseVersion()
{
  m_containerDir.ClearFreeLists(2);
  m_isOpen = false;
}

/*----------------------------------------------------------------------*/

inline tsp00_Int4 OMS_Context::CurrentVersionKey() const 
{
  return m_versionContext.ovc_key;
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::DecNewObjectsToFlush()
{
  --m_cntNewObjectsToFlush;
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::DeleteObjInContext (OmsObjectContainerPtr p, OMS_ClassIdEntry* clsinfo)
{
    OMS_DETAIL_TRACE(p->IsNewObject() ? (omsTrContext | omsTrNewObj) : omsTrContext, 
        m_session->m_lcSink, "OMS_Context::DeleteObjInContext : " << p->m_oid
        << ", class: " << clsinfo->GetClassInfoPtr()->GetClassName());
    
    if (p->IsVerNewRegistered())
        m_newObjCache.removeObject(p, this);

    const bool c_updateKeyCache = true;
    bool found = m_oidDir.HashDelete(p->m_oid, c_updateKeyCache);
    
    if (NULL != clsinfo && found) {
        clsinfo->chainFree(*this, p, 6);
    }
}

/*----------------------------------------------------------------------*/

inline bool OMS_Context::ExistsConsistentView() 
{
  return (!(m_consistentView.gg90IsNil()));
}

/*----------------------------------------------------------------------*/

// PTS 1125361 added new parameter ignore Generation
inline OmsObjectContainerPtr OMS_Context::FindObjInContext (const OmsObjectId* pOid, bool ignoreGeneration) 
{
  return m_oidDir.HashFind(pOid, ignoreGeneration);
}

/*----------------------------------------------------------------------*/

inline OmsObjectContainerPtr OMS_Context::FindVarObjInContext (const OmsObjectId& oid, OMS_VarObjLockType lockReq, unsigned long size, void* buf) 
{
  const char* msg = "OMS_Context::FindVarObjInContext";
  OmsObjectContainerPtr po = this->FindObjInContext (&oid);
  if (NULL != po) {
    if (po->DeletedFlag()) {
      m_session->ThrowDBError (e_object_not_found, msg, oid, __MY_FILE__, __LINE__);
    }
    OMS_VarObjInfo* pObjInfo = REINTERPRET_CAST (OMS_VarObjInfo*, &po->m_pobj);
    pObjInfo->lock(lockReq);
    if (pObjInfo->m_vobjSize > size) {
      m_session->ThrowDBError (e_too_small_packet_size, msg, oid, __MY_FILE__, __LINE__);
    }
    if (NULL != buf) {
      SAPDB_MemCopyNoCheck (buf, pObjInfo->m_pvobj, pObjInfo->m_vobjSize);
    }
    return po;
  }
  return NULL;
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::deallocate(void* p) 
{
#ifdef USE_SYSTEM_ALLOC_CO13
  delete[] (char*) p;
#else
  m_heap.Deallocate(p);
#endif
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::FreeVarObj(unsigned char* p, size_t sz) 
{
  this->deallocate (p);
}

/*----------------------------------------------------------------------*/

inline OMS_GuidEntry* OMS_Context::GetClassInfo(const ClassIDRef guid) 
{
  return m_containerDir.GetClassInfo (guid);
}

/*----------------------------------------------------------------------*/

inline OMS_ClassIdEntry* OMS_Context::GetContainerInfo(tsp00_Uint4 containerHandle) 
{
  return m_containerDir.HashFindViaContainerHandle(containerHandle);
}

/*----------------------------------------------------------------------*/

inline OMS_ClassIdEntry* OMS_Context::GetContainerInfoReg(tsp00_Uint4 containerHandle) 
{
  return m_containerDir.HashFindViaContainerHandle(containerHandle, true, true);
}

/*----------------------------------------------------------------------*/

inline OMS_ClassIdEntry* OMS_Context::GetContainerInfoNoCheck(tsp00_Uint4 containerHandle) 
{
  return m_containerDir.HashFindViaContainerHandle(containerHandle, false);
}

/*----------------------------------------------------------------------*/

inline OMS_Session* OMS_Context::GetCurrentSession() 
{
  return m_session;
}

/*----------------------------------------------------------------------*/


inline tsp00_Int4 OMS_Context::GetHashSize() const
{
  return m_oidDir.GetHashSize();
}

/*----------------------------------------------------------------------*/

inline OMS_Context* OMS_Context::GetNext() const
{
  return m_next;
}

/*----------------------------------------------------------------------*/

inline OMS_Context* OMS_Context::GetNextUnloaded() const
{
  return m_nextUnloaded;
}

/*----------------------------------------------------------------------*/

inline OmsObjectContainerPtr OMS_Context::GetObj(const OmsObjectId& oid, bool doLock) 
{
  m_session->IncDeref();
  OmsObjectContainerPtr pObj = m_oidDir.HashFind(&oid);//this->FindObjInContext(&oid);
  if (NULL != pObj) {
    if (pObj->DeletedFlag()) {
      return NULL; // PTS 1107036
    }
    if ((doLock) && (!pObj->LockedFlag()) && (!this->IsVersion())) {
      this->LockObj(pObj->m_oid);
    }
  }
  else {
    pObj = this->GetObjFromLiveCacheBase(oid, doLock ? OMS_Context::Lock : OMS_Context::NoLock);
  }
  return pObj;
}


/*----------------------------------------------------------------------*/

inline OmsObjectContainerPtr OMS_Context::GetObj(const ClassIDRef guid, const OmsObjectId& oid, bool doLock) 
{
  m_session->IncDeref();
  OmsObjectContainerPtr pObj = this->FindObjInContext(&oid);
  if (NULL != pObj) {
    if (pObj->DeletedFlag()) {
      return NULL; // PTS 1107036
    }
    if ((doLock) && (!pObj->LockedFlag()) && (!this->IsVersion())) {
      this->LockObj(pObj->m_oid);
    }
  }
  else {
    pObj = this->GetObjFromLiveCacheBase(guid, oid, doLock ? OMS_Context::Lock : OMS_Context::NoLock);
  }
  this->CheckCompatibility(guid, pObj);
  
  return pObj;
}

/*----------------------------------------------------------------------*/

inline OmsObjectContainerPtr OMS_Context::GetObjFromLiveCacheBase(const OmsObjectId& oid,
                                                                  LockType           doLockObj,
                                                                  bool               mayBeVarObject)
                                                                      
{
  const char* msg = "OMS_Context::GetObjFromLiveCacheBase_1";
  int              objLen;
  int              objHistReadCount;
  tgg00_BasisError DBError;
  if (this->IsVersion()) {
    doLockObj = OMS_Context::NoLock;
  }
  OMS_UnknownContainerId FileId;
  m_session->m_currVarObjChunk.Clear();
  m_session->m_currVarObjChunk.m_seq.gg91SetNilRef();  // PTS 1121449

  OMS_HResult hr = m_currLcSink->GetObj (
    m_consistentView,
    FileId,
    m_pVersionContext,
    *REINTERPRET_CAST(OmsTypeOid*, CONST_CAST(OmsObjectId*, &oid)),
    doLockObj != NoLock,  
    m_session->m_currVarObjChunk.m_seq,
    sizeof(m_session->m_currVarObjChunk.m_container), 
    ((unsigned char*) &m_session->m_currVarObjChunk.m_container), 
    objLen,
    objHistReadCount,
    DBError);
  if (0 == DBError) {
    OmsObjectContainerPtr pObj;
    if (FileId.IsVarObjFile()) {
      if (!mayBeVarObject)
      {
          return NULL;
      }
      m_session->m_currVarObjChunk.m_containerHandle = FileId.GetContainerHandle();
      if (objLen <= VAR_OBJ_CHUNK_SIZE) {
        m_session->m_currVarObjChunk.m_container.m_vobjSize = objLen;
      }
      pObj = this->LoadVarObject (*REINTERPRET_CAST(const OmsVarOid*, &oid), VarObjNoLock, 
        m_session->m_currVarObjChunk.m_container.m_vobjSize, m_session->m_currVarObjChunk, NULL);
    }
    else {
      OMS_ClassIdEntry* containerInfo = this->GetContainerInfo(FileId.GetContainerHandle());
      pObj = m_session->GetMemory (*containerInfo);
      SAPDB_MemCopyNoCheck (REINTERPRET_CAST(unsigned char*, &pObj->m_pobj) + sizeof(void*), &m_session->m_currVarObjChunk.m_container,
        containerInfo->GetPersistentSize());
      pObj->m_oid    = oid;
      pObj->m_objseq = m_session->m_currVarObjChunk.m_seq;
      PutObjectIntoContext(pObj, FileId.GetContainerHandle());
    }
    if (doLockObj) {
      pObj->MarkLocked();
    }
    return pObj;
  }
  else {
    if (e_object_not_found != DBError) {
      switch (doLockObj) {
      case OMS_Context::Lock:
        LockResult (DBError, NULL, oid, msg);
        break;
      case OMS_Context::TryLock:
        if (!TryLockResult (DBError, NULL, oid, msg)) {
          // retry without the lock
          return GetObjFromLiveCacheBase(oid, NoLock, mayBeVarObject);
        }
        break;
      }
      this->CheckDBError(DBError, msg, oid);
    }
    return NULL;
  }
}

/*----------------------------------------------------------------------*/

inline OmsObjectContainerPtr OMS_Context::GetObjFromLiveCacheBase(const ClassIDRef   guid, 
                                                                  const OmsObjectId& oid,
                                                                  LockType           doLockObj,
                                                                  tgg91_PageRef*     pObjVers)
{
  int              dummyLen;
  int              objHistReadCount;
  tgg00_BasisError DBError;
  const char* msg = "OMS_Context::GetObjFromLiveCacheBase_2";
  
  m_session->IncDereflC();
  OMS_GuidEntry* pClassInfo = this->GetClassInfo(guid);
  if (pClassInfo->IsBaseClass()) {
    // oid may identifiy an object of a derived class, i.e. size is unknown
    return this->GetObjFromLiveCacheBase(oid, doLockObj);
  }
  else {
    OmsObjectContainerPtr pObj = m_session->GetMemory (*pClassInfo);
    if (pObjVers)   // PTS 1121449
      pObj->m_objseq = *pObjVers;
    else
      pObj->m_objseq.gg91SetNilRef();

    if (this->IsVersion()) {
      doLockObj = OMS_Context::NoLock;
    }
    OMS_UnknownContainerId FileId;
    OMS_HResult hr = m_currLcSink->GetObj (
      m_consistentView,
      FileId,
      m_pVersionContext,
      *REINTERPRET_CAST(OmsTypeOid*, CONST_CAST(OmsObjectId*, &oid)),
      doLockObj != NoLock,  
      pObj->m_objseq,
      pClassInfo->GetObjectSize() - OmsObjectContainer::headerSize() - sizeof(void*), // object size - header - vtblptr
      ((unsigned char*) &pObj->m_pobj) + sizeof(void*), 
      dummyLen,
      objHistReadCount,
      DBError);
    if (0 != DBError) {
      pClassInfo->ChainFree(*this, pObj, 50); 
      if (e_object_not_found != DBError) {
        switch (doLockObj) {
        case OMS_Context::Lock:
          LockResult(DBError, pObj, oid, msg);
          break;
        case OMS_Context::TryLock:
          if (!TryLockResult(DBError, pObj, oid, msg)) {
            // retry without the lock
            return GetObjFromLiveCacheBase(guid, oid, NoLock, pObjVers);
          }
          break;
        }
        this->CheckDBError(DBError, msg, oid);
      }
      return NULL;
    }
    pObj->m_oid = oid;
    if (doLockObj != OMS_Context::NoLock) {
      pObj->MarkLocked();
    }
    //if (addIntoObjCache) {
    PutObjectIntoContext(pObj, FileId.GetContainerHandle());
    //};
    m_session->IncLogHop(objHistReadCount);
    return pObj;
  }
}

/*----------------------------------------------------------------------*/

inline int OMS_Context::LoadBaseClsObjsFromLiveCacheBase(int                 noOfOid,
                                                        const OmsObjectId   *pOid,
                                                        tgg91_PageRef       *pObjVers,
                                                        bool                 doLock,
                                                        OmsObjectContainer **ppObjContainer,
                                                        tgg00_BasisError    *pDBError,
                                                        OmsAbstractObject  **ppObj,
                                                        OMS_GuidEntry      **ppClassInfo,
                                                        tgg01_ContainerId   *pContainerId,
                                                        int                 *pObjSize)
{
  // oid may identifiy an object of a derived class, i.e. size is unknown.
  // Therefore first get container (and thereby the size) from the kernel and
  // then deref objects with known sizes.

  // Get container id from kernel 
  OMS_HResult hr = m_currLcSink->GetContainerId (
      pContainerId,
      m_pVersionContext,
      noOfOid,
      REINTERPRET_CAST(const OmsTypeOid*, pOid),
      pDBError);

  // Determine correct class-info for oids
  for (int i=0; i<noOfOid; ++i){
    if (i>0 && pContainerId[i].fileObjFileNo_gg00() == pContainerId[i-1].fileObjFileNo_gg00()){
      ppClassInfo[i] = ppClassInfo[i-1];
    }
    else {
      OMS_ClassIdEntry* pClsIdEntry = m_containerDir.HashFindViaContainerHandle(pContainerId[i].fileObjFileNo_gg00());
      ppClassInfo[i] = m_containerDir.GetClassInfo(pClsIdEntry->GetContainerInfoPtr()->m_clsInfo->GetGuid());
    }
  }

  // Mass-Deref with known sizes
  int errorCnt 
    = LoadObjsFromLiveCacheBase(noOfOid,
                                pOid,
                                pObjVers,
                                doLock,
                                ppObjContainer,
                                pDBError,
                                ppObj,
                                ppClassInfo,
                                pContainerId,
                                pObjSize);

  return errorCnt;
}

/*----------------------------------------------------------------------*/

inline int OMS_Context::LoadObjsFromLiveCacheBase(int                  noOfOid,
                                                  const OmsObjectId   *pOid,
                                                  tgg91_PageRef       *pObjVers,
                                                  bool                 doLock,
                                                  OmsObjectContainer **ppObjContainer,
                                                  tgg00_BasisError    *pDBError,
                                                  OmsAbstractObject  **ppObj,
                                                  OMS_GuidEntry      **ppClassInfo,
                                                  tgg01_ContainerId   *pContainerId,
                                                  int                 *pObjSize)

{
  const char* msg = "OMS_Context::LoadObjsFromLiveCacheBase ";

  int            i;
  int            objHistReadCount = 0;
  int            DBErrorCnt       = 0;
  
  m_session->IncDereflC();

  for(i=0; i<noOfOid; ++i){
    // Determine size of the object
    pObjSize[i] = ppClassInfo[i]->GetObjectSize();

    // Get object frame to store the objects
    ppObjContainer[i] = m_session->GetMemory (*ppClassInfo[i]);

    // Determine position where the kernel should write the object to. As the vtbl-pointer
    // is stored at the beginning of the abstract object the position must be incremented
    // by the size of a pointer.)
    ppObj[i] = (OmsAbstractObject*) ((unsigned char*) (&ppObjContainer[i]->m_pobj) + sizeof(void*));
  }

  // Read objects from the kernel
  OMS_HResult hr = m_currLcSink->GetObjects (
      m_consistentView,
      pContainerId,
      m_pVersionContext,
      noOfOid,
      REINTERPRET_CAST(const OmsTypeOid*, pOid),
      pObjVers,
      pObjSize, 
      IsVersion() ? false : doLock, 
      REINTERPRET_CAST(unsigned char**, ppObj),
      objHistReadCount,
      DBErrorCnt,
      pDBError);

  // Error handling
  if (DBErrorCnt > 0) {
    for (i=0; i<noOfOid; ++i){
      if (pDBError[i] != 0){
        // Release allocated memory
        ppClassInfo[i]->ChainFree(*this, ppObjContainer[i], 51); 
        ppObjContainer[i] = NULL;

        if (pDBError[i] == e_object_not_found){
        }
        else if (pDBError[i] == e_object_dirty) {
          m_session->IncOutOfDate();
        }
        else {
          // Release allocated memory for all remaining objects
          for(int j=i ; j<noOfOid; ++j){
            ppClassInfo[j]->ChainFree(*this, ppObjContainer[j], 52); 
            ppObjContainer[j] = NULL;
            pDBError[j]       = -1;
          }

          m_session->ThrowDBError (pDBError[i], msg, pOid[i], __MY_FILE__, __LINE__);
          return DBErrorCnt;
        }
      }
    }
  }

  for (i=0; i<noOfOid; ++i){
    if (ppObjContainer[i] != NULL){
      ppObjContainer[i]->m_oid    = pOid[i];
      ppObjContainer[i]->m_objseq = pObjVers[i];

      if (doLock && !IsVersion()) {
        // Locally mark object as locked if lock is requested
        ppObjContainer[i]->MarkLocked();
      }

      // Insert Object into the oid-hash
      PutObjectIntoContext(ppObjContainer[i], pContainerId[i].fileObjFileNo_gg00());
    }
  }
  
  // Update statistics
  m_session->IncLogHop(objHistReadCount);

  return DBErrorCnt;
}


/*======================================================================*/
/// Reading object with the specified key. 
/*! If not being in a version, the object is requested from the livecache 
**  kernel. It it's found then the oid is known and with this oid it is
**  checked whether this object is already stored in the local context
**  cache. If it is not already stored, then it is copied.
**  If a version is active, then it is first checked whether the key is
**  registerd in the search structure m_index. If so a pointer to the 
**  location in memory can be found there. (This check is needed, as 
**  objects which are newly created in a version are not stored in the 
**  livecache kernel and therefore they are accessible only via this
**  structure. 
**  \param ContainerInfo Reference to the container information in the 
**    local container dictionary
**  \param key Key of the requested object
**  \param doLock should the method aquire a lock on the object. If the 
**    current transaction already owns a lock and a lock is requested
**    again, then this request is ignored. 
**  \return A pointer to the object in the context cache is returned if 
**    an object for the specified key exist; otherwise NULL
**  \see GetObjViaCachedKey 
**  \since 7.4.3  PTS 1117571 
*/
/*======================================================================*/
inline OmsObjectContainerPtr OMS_Context::GetObjViaKey(OMS_ClassIdEntry &ContainerInfo, 
                                                       unsigned char    *key, 
                                                       bool              doLock) 
{
  const char* msg = "OMS_Context::GetObjViaKey";

  m_session->IncDerefKey();

  // Get memory into which the kernel can copy the object
  OmsObjectContainer* obj = m_session->GetMemory(ContainerInfo);

  // transform key into binary representation
  unsigned char* pBinaryKey = ContainerInfo.GetKeyPtr(obj);
  // introduce pAbstractObject, without this code call will not be virtual on some platforms
  OmsAbstractObject* pAbstractObject = &obj->m_pobj;
  pAbstractObject->omsKeyToBinary(key, pBinaryKey);

  if (IsVersion()) {
    // If object has been created in a version, then it is stored in the search tree for all
    // version objects. As access to this structure is much faster than access to the kernel
    // first check this structure. (see PTS 1121876)
    OmsObjectContainer* found = ContainerInfo.VersionFindKey(pBinaryKey);
    if (found) {
      // Release memory
      ContainerInfo.chainFree(*this, obj, 7);

      m_session->IncCacheHit(found->m_oid);

      return found->DeletedFlag() 
               ? NULL
               : found;
    }
  }

  // Request object from the kernel
  int                 ObjHistReadCount;
  tgg00_BasisError    DBError;
  OMS_HResult hr = m_currLcSink->GetObjWithKey (
    (unsigned char*) &m_consistentView,
    (unsigned char*) &ContainerInfo.GetFileId(),
    VersionContext(),
    ContainerInfo.GetKeyDesc().GetLen(),   // PTS 1122540
    pBinaryKey, 
    IsVersion() ? false : doLock, 
    ContainerInfo.GetPersistentSize(),
    ((unsigned char*) &obj->m_pobj) + sizeof(void*),
    REINTERPRET_CAST(OmsTypeOid*, &obj->m_oid),
    (unsigned char*) &obj->m_objseq,
    &ObjHistReadCount,
    &DBError);
  m_session->IncLogHop(ObjHistReadCount);  

  if (DBError) {
    // Release memory
    ContainerInfo.chainFree(*this, obj, 8);

    if (e_hash_key_not_found != DBError) {
      // Error handling
      LockResult (DBError, NULL, OmsObjectId(), msg);
      return NULL;
    }
    else {
      // There is no object with such a key 
      return NULL;
    }
  }
  else {
    if (doLock && !IsVersion()) {
      // Lock object if requested
      LockResult (DBError, obj, OmsObjectId(), msg);
    }

    // Check whether the object with the corresponding oid is already stored in the oms-cache
    OmsObjectContainer* found = FindObjInContext(&obj->m_oid, true /*ignoreGeneration*/);  // PTS 1125361
    if (NULL == found) {
      // Object does not exist locally. Therefore insert object into oms-cache
      PutObjectIntoContext (obj, ContainerInfo.GetContainerHandle());
      return obj;
    }
    else {
      // Object exists already in the oms-cache
      found->m_objseq = obj->m_objseq;
      if (doLock && !IsVersion()) {
        // Mark object in the object container as locked 
        found->MarkLocked();
      }

      // Release memory of object read from the kernel
      ContainerInfo.chainFree(*this, obj, 9);
      
      return found->DeletedFlag()
             ? NULL
             : found;
    }  
  }
}


/*======================================================================*/
/// Reading object with the specified key using cached keys. 
/*! First the search structure m_index is checked whether the object does 
**  already exist in the current context. 
**  If so no access to the kernel is needed. Otherwise the livecache kernel
**  is requested and if the object exists there it is copied into the context
**  cache. If an object is not found at all,
**  then this is also registered in a search structure (m_cacheMiss), so
**  that later requests for this object can be answered quickly, too.
**  \param ContainerInfo Reference to the container information in the local
**    container dictionary
**  \param key Key of the requested object
**  \param doLock should the method aquire a lock on the object. If the 
**    current transaction already owns a lock and a lock is requested
**    again, then this request is ignored. 
**  \return A pointer to the object in the context cache is returned if an  
**    object for the specified key exist; otherwise NULL
**  \see GetObjViaKey 
**  \since 7.4.3  PTS 1117571 
*/
/*======================================================================*/
inline OmsObjectContainerPtr 
OMS_Context::GetObjViaCachedKey(OMS_ClassIdEntry& ContainerInfo, 
                                unsigned char* key, 
                                bool doLock) 
{
    
    const char* msg = "OMS_Context::GetObjViaCachedKey";
    
    int                 ObjHistReadCount;    
    tgg00_BasisError    DBError;
    
    
    m_session->IncDerefKey();
    
    OmsObjectContainer* obj = m_session->GetMemory(ContainerInfo);
    
    // transform key into binary representation
    unsigned char* pBinaryKey = ContainerInfo.GetKeyPtr(obj);
    
    // introduce pAbstractObject, without this code call will not be virtual 
    // on some platforms
    OmsAbstractObject* pAbstractObject = &obj->m_pobj;
    pAbstractObject->omsKeyToBinary(key, pBinaryKey);
    
    // ********** Try to read from cache **********
    OmsObjectContainerPtr found = ContainerInfo.VersionFindKey(pBinaryKey);
    if (found) {
        m_session->IncCacheHit(found->m_oid);
        
        // Release memory
        ContainerInfo.chainFree(*this, obj, 10);
        
        if (doLock && !found->LockedFlag() && !IsVersionOid(found->m_oid)) {
            // Get lock if requested. As the object has been read from the kernel
            // without aquireing a lock, the kernel must be informed about the lock, too.
            m_session->LockObj(found); 
            found->MarkLocked();
        }
        
        // If object is not marked as deleted, then return cached Entry.
        return found->DeletedFlag() ? NULL : found;
    }
    
    // ********** Check whether key is known as a cache miss **********
    else if (ContainerInfo.IsCacheMiss(pBinaryKey)) {
        m_session->IncCacheMiss();		
        
        // Release memory
        ContainerInfo.chainFree(*this, obj, 11);
        
        return NULL;
    }
    // ********** Get object from kernel **********
    else {
        
        OMS_HResult hr = m_currLcSink->GetObjWithKey (
            (unsigned char*) &m_consistentView,
            (unsigned char*) &ContainerInfo.GetFileId(),
            VersionContext(),
            ContainerInfo.GetKeyDesc().GetLen(),  // PTS 1122540
            pBinaryKey, 
            doLock && !IsVersion(),  // lock only if not in version 
            ContainerInfo.GetPersistentSize(),
            ((unsigned char*) &obj->m_pobj) + sizeof(void*),
            REINTERPRET_CAST(OmsTypeOid*, &obj->m_oid),
            (unsigned char*) &obj->m_objseq,
            &ObjHistReadCount,
            &DBError);
        
        m_session->IncLogHop(ObjHistReadCount);  
        
        if (DBError) {
            // Read from kernel was not successful 
            
            // Release Memory
            ContainerInfo.chainFree(*this, obj, 12);
            
            
            if (DBError == e_hash_key_not_found) {
                // Object does not exist neither in the cache nor in the kernel
                // => Insert Object into the cache miss structure
                ContainerInfo.InsertCacheMiss(pBinaryKey, this);   
            }
            else {
                // ONLY Errorhandling as object==NULL
                LockResult (DBError, NULL, OmsObjectId(), msg);    
            }
            
            return NULL;
        }
        else {
            // Read from kernel was successful
            
            found = FindObjInContext(&obj->m_oid, true /*ignoreGeneration*/);  // PTS 1125361
            if (!found) {
                
                // Insert entry into cached key structure 
                ContainerInfo.VersionAddKey(obj, this);    
                
                PutObjectIntoContext (obj, ContainerInfo.GetContainerHandle()); 
                
                if (doLock) {
                    LockResult (DBError, obj, OmsObjectId(), msg);
                }
                
                return obj;
            }
            else {
                // Object is already in the context without being registered in
                // the cache structure. This can either happen if object was not read
                // via the key or if the caching was switched on after objects have 
                // already been loaded into the context
                
                found->m_objseq = obj->m_objseq;
                ContainerInfo.chainFree(*this, obj, 13);
                
                if (doLock && !found->LockedFlag()) {
                    found->MarkLocked();
                }
                
                // Insert info for cached keys 
                ContainerInfo.VersionAddKey(found, this);   
                
                return found->DeletedFlag() ? NULL : found;
            }
        }
    }	
}


/*----------------------------------------------------------------------*/
// PTS 1122194
inline int OMS_Context::LoadObjsViaKeyFromLCBase(int                   noOfObj,
                                                  tsp00_Int4          *pKeyLen,
                                                  unsigned char      **ppBinaryKey,
                                                  OmsObjectId         *pOid,
                                                  tgg91_PageRef       *pObjVers,
                                                  bool                 doLock,
                                                  OmsObjectContainer **ppObjContainer,
                                                  tgg00_BasisError    *pDBError,
                                                  OmsAbstractObject  **ppObj,
                                                  OMS_ClassIdEntry   **ppClsInfo,
                                                  tgg01_ContainerId   *pContainerId,
                                                  int                 *pObjSize)
{
  const char* msg = "OMS_Context::LoadObjsViaKeyFromLCBase ";

  tsp00_Int4 DBErrorCnt = 0;

  // Read objects from the kernel
  tsp00_Int4 objHistReadCount = 0;
  OMS_HResult hr = m_currLcSink->GetObjectsWithKey (
      &m_consistentView,
      pContainerId,
      m_pVersionContext,
      pKeyLen,
      noOfObj,
      ppBinaryKey,
      IsVersion() ? false : doLock,
      pObjSize, 
      REINTERPRET_CAST(unsigned char**, ppObj),
      REINTERPRET_CAST(OmsTypeOid*, pOid),
      pObjVers,  
      objHistReadCount,
      DBErrorCnt,
      pDBError);

  // Error handling
  if (DBErrorCnt > 0) {
    for (int i=0; i<noOfObj; ++i){
      if (pDBError[i] != 0){
        // Release allocated memory
        ppClsInfo[i]->chainFree(*this, ppObjContainer[i], 14); 
        ppObjContainer[i] = NULL;

        if (pDBError[i] == e_hash_key_not_found){
        }
        else if (pDBError[i] == e_object_dirty) {
          m_session->IncOutOfDate();
        }
        else {
          //// Release allocated memory for all remaining objects
          //for(int j=i ; j<noOfObj; ++j){
          //  ppClsInfo[j]->chainFree(*this, ppObjContainer[j], 15); 
          //  ppObjContainer[j] = NULL;
          //  pDBError[j]       = -1;
          //}

          //m_session->ThrowDBError (pDBError[i], msg, pOid[i], __MY_FILE__, __LINE__);
          //return DBErrorCnt;
        }
      }
    }
  }

  for (int i=0; i<noOfObj; ++i){
    if (ppObjContainer[i] != NULL){
      OmsObjectContainer* found = FindObjInContext(&pOid[i], true /*ignoreGeneration*/);
      if (found){
        // Object is already stored in the oms-cache
        ppClsInfo[i]->chainFree(*this, ppObjContainer[i], 16);
        ppObjContainer[i] = found;

        ppObjContainer[i]->m_objseq = pObjVers[i];
      }
      else {
        // Object is not stored in the oms-cache
        ppObjContainer[i]->m_oid    = pOid[i];
        ppObjContainer[i]->m_objseq = pObjVers[i];

        PutObjectIntoContext(ppObjContainer[i], pContainerId[i].fileObjFileNo_gg00());
      }

      if (doLock && !IsVersion()) {
        // Locally mark object as locked if lock is requested
        ppObjContainer[i]->MarkLocked();
      }
    }
  }
  
  // Update statistics
  m_session->IncLogHop(objHistReadCount);

  return DBErrorCnt;
}

/*----------------------------------------------------------------------*/

inline int OMS_Context::GetVarObjFromLiveCacheBase(const OmsObjectId& oid, bool doLock)
{
  int                 objLen;
  int                 objHistReadCount;
  tgg00_BasisError    DBError;
  OMS_UnknownContainerId FileId;
  const char* msg = "OMS_Context::GetVarObjFromLiveCacheBase";
  m_session->IncLoadVarObjLC();

  m_session->m_currVarObjChunk.m_seq.gg91SetNilRef();  // PTS 1121449
  m_session->m_currVarObjChunk.m_container.m_vobjNext.setNil();
  m_session->m_currVarObjChunk.m_container.m_vobjSize = 0;

  OMS_HResult hr = m_currLcSink->GetObj (
    m_consistentView,
    FileId,
    m_pVersionContext,
    *REINTERPRET_CAST(OmsTypeOid*, CONST_CAST(OmsObjectId*, &oid)),
    doLock, 
    m_session->m_currVarObjChunk.m_seq, 
    sizeof(m_session->m_currVarObjChunk.m_container),
    (unsigned char*) &m_session->m_currVarObjChunk.m_container,
    objLen, objHistReadCount, DBError);
  if ( DBError != 0 ) 
  { 
    if (e_object_not_found != DBError) 
    {
      if (doLock) 
      {
        LockResult (DBError, NULL, oid, msg);
      }
    }
    this->CheckDBError(DBError, msg, oid);
    return -1;
  }
  if (!FileId.IsVarObjFile()) {
    m_session->ThrowDBError (e_object_not_found, msg, oid, __MY_FILE__, __LINE__);
  }
  m_session->m_currVarObjChunk.m_containerHandle = FileId.GetContainerHandle();
  m_session->IncLogHop(objHistReadCount);
  m_session->m_currVarObjChunk.m_oid = oid;
  if (objLen <= VAR_OBJ_CHUNK_SIZE) {
    m_session->m_currVarObjChunk.m_container.m_vobjSize = objLen;
  }
  return m_session->m_currVarObjChunk.m_container.m_vobjSize;
}

/*----------------------------------------------------------------------*/

inline tsp00_8ByteCounter OMS_Context::HeapUsed()
{
#ifdef USE_SYSTEM_ALLOC_CO13
  return 0;
#else
  SAPDB_ULong BytesUsed;
  SAPDB_ULong MaxBytesUsed;
  SAPDB_ULong BytesControlled;
  m_heap.CalcStatisticsConst(BytesUsed, MaxBytesUsed, BytesControlled); 
  return BytesUsed;
#endif
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::IncNewObjectsToFlush()
{
  ++m_cntNewObjectsToFlush;
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::IncVersionKey ()
{
  ++m_versionContext.ovc_key;
}

/*----------------------------------------------------------------------*/

inline bool OMS_Context::IsOpenVersion (const OmsVersionId& versionId) 
{
  return (0 == memcmp (versionId, m_version, sizeof(versionId)));
}

/*----------------------------------------------------------------------*/

inline bool OMS_Context::IsUnloadable() 
{
  return ((!m_isOpen) && (!m_boundToTrans));
}

/*----------------------------------------------------------------------*/

inline bool OMS_Context::IsVersion() 
{
  return m_isVersion;
}

/*----------------------------------------------------------------------*/

inline bool OMS_Context::IsVersionOid (const OmsObjectId& oid) const 
{
  return (oid.getPno() == OMS_VERSION_OBJ_PAGE_NO);
}

/*----------------------------------------------------------------------*/

inline bool OMS_Context::IsVersionOpen() 
{
	return m_isOpen;
}

/*----------------------------------------------------------------------*/

inline OmsObjectContainerPtr OMS_Context::LoadVarObject (const OmsVarOid& oid, OMS_VarObjLockType lockReq, 
                                                         tsp00_Int4 objSize, OMS_VarObjChunk& chunk, void* buf) 
{
  OMS_VarObjInfo*     pObjInfo;
  unsigned char*          p;
  tsp00_Int2              DBError;
  OMS_VarObjInfoNode* pInfoNode;
  OmsObjectId             nextOid;
  int                     objLen;
  int                     ObjHistReadCount;

  /* first chunk of var object ist expected in parameter chunk ! */

  const char* msg = "OMS_Context::LoadVarObject";
  
  OMS_UnknownContainerId   FileId;
  OMS_GuidEntry* pClassInfo   = this->GetClassInfo(OMS_VAR_OBJ_GUID);
  OmsObjectContainerPtr po      = m_session->GetMemory(*pClassInfo);
  tsp00_Int4            moveLen = OMS_Globals::Min(objSize, VAR_OBJ_CHUNK_SIZE);
  po->m_oid     = oid;
  po->m_objseq  = chunk.m_seq;
  po->MarkVarObj();
  pObjInfo = new(&po->m_pobj) OMS_VarObjInfo(oid, objSize, chunk.m_seq); 
  pObjInfo->lock(lockReq);
  pObjInfo->m_pvobj               = m_session->GetVarObjMemory(objSize);
  pObjInfo->m_vobjInfo.m_vobjOid  = oid;
  pObjInfo->m_vobjInfo.m_vobjSeq  = chunk.m_seq;
  pObjInfo->m_vobjInfo.m_nodeCnt  = 1;   // PTS 1121449
  pObjInfo->m_vobjInfo.m_vobjNext = NULL;
  pInfoNode = &pObjInfo->m_vobjInfo;
  objSize  -= moveLen;
  if (!this->PutObjectIntoContextReg (po, chunk.m_containerHandle)) {
    // auto register varobj container
    GUID			   guid;
    OmsSchemaHandle  schema;
    OmsContainerNo   cno;
    tgg00_BasisError DBError;
    m_currLcSink->GetContainerInfo (chunk.m_containerHandle, guid, schema, cno, DBError);
    if (0 == DBError) {
      m_session->RegVarObjectContainer(schema, cno);
      this->PutObjectIntoContext (po, chunk.m_containerHandle);
    }
    else {
      m_session->ThrowDBError(DBError, msg, __MY_FILE__, __LINE__);
    }
  }
  SAPDB_MemCopyNoCheck (pObjInfo->m_pvobj, &chunk.m_container, moveLen);
  p  = pObjInfo->m_pvobj + moveLen;
  try {
    bool overflow = false;                            // PTS 1121449
    OMS_VarObjInfoNode *pFirstInfoNode = pInfoNode;   // PTS 1121449

    while (objSize > 0) {
      nextOid = chunk.m_container.m_vobjNext;
      m_session->Set_OidOfLastObject(nextOid);

      if (!nextOid){
        m_session->ThrowDBError(e_invalid_oid, "Error dereferencing continuation object-1-", oid, __MY_FILE__, __LINE__);
      }

      moveLen = OMS_Globals::Min(objSize, VAR_OBJ_CHUNK_SIZE);
      chunk.m_seq.gg91SetNilRef();             // PTS 1121449
      chunk.m_container.m_vobjNext.setNil();
      chunk.m_container.m_vobjSize = 0;

      OMS_HResult hr = m_currLcSink->GetObj (
        m_consistentView,
        FileId,
        m_pVersionContext,
        *REINTERPRET_CAST(OmsTypeOid*, &nextOid),
        false,  
        chunk.m_seq,
        sizeof (chunk.m_container),
        (unsigned char*) &chunk.m_container, 
        objLen,
        ObjHistReadCount,
        DBError);
      this->CheckDBError(DBError, msg, oid);

      if (moveLen > objLen){
        m_session->ThrowDBError(e_invalid_oid, "Error dereferencing continuation object-2-", oid, __MY_FILE__, __LINE__);
      }

      SAPDB_MemCopyNoCheck (p, &chunk.m_container, moveLen);
      p       += moveLen;
      objSize -= moveLen;
      pInfoNode->m_vobjNext = new(*this) OMS_VarObjInfoNode (nextOid, chunk.m_seq);
      
      // Remember how many pages or infonodes belong to current object (PTS 1121449)
      // As objects can be arbitrary large prevent overflow of 'unsigned short'-counter.
      if (!overflow && pFirstInfoNode->m_nodeCnt < (1<<(sizeof(unsigned short)<<3))-2){
        ++pFirstInfoNode->m_nodeCnt;   
      }
      else {
        pFirstInfoNode->m_nodeCnt = 0;
        overflow = true;
      }

      pInfoNode = pInfoNode->m_vobjNext;
    }
    if (buf != NULL) {
      SAPDB_MemCopyNoCheck (buf, pObjInfo->m_pvobj, pObjInfo->m_vobjSize);
    }
  } 
  catch (DbpError &e) {
    // remove varobj from context in case of error
    pObjInfo->unlock();
    this->DeleteObjInContext(po, po->GetContainerInfo(this));
    throw e;
  }
  return po;
}

/*----------------------------------------------------------------------*/


inline void OMS_Context::LockObj( const OmsObjectId&oid ) 
{
  const char* msg = "OMS_Context::LockObj";
    
  m_session->AssertNotReadOnly(msg);
  if (this->IsVersion()) {
    return;
  }
  OmsObjectContainerPtr pObj = this->FindObjInContext(&oid);
  if (NULL != pObj) {
    if (pObj->DeletedFlag()) {
      m_session->ThrowDBError(e_object_not_found, msg, oid, __MY_FILE__, __LINE__);
    }
    if (pObj->LockedFlag()) {
      // Object already locked
      return;
    }
    m_session->LockObj(pObj);
  }
  else {
    pObj = this->GetObjFromLiveCacheBase(oid, OMS_Context::Lock); 
    if (NULL == pObj) {
      m_session->ThrowDBError (e_object_not_found, msg, oid, __MY_FILE__, __LINE__);
    }
  }
}

/*----------------------------------------------------------------------*/

inline bool OMS_Context::TryLockObj( const OmsObjectId&oid ) 
{
  const char* msg = "OMS_Context::LockObj";
    
  m_session->AssertNotReadOnly(msg);
  if (this->IsVersion()) {
    return true;
  }
  OmsObjectContainerPtr pObj = this->FindObjInContext(&oid);
  if (NULL != pObj) {
    if (pObj->DeletedFlag()) {
      m_session->ThrowDBError(e_object_not_found, msg, oid, __MY_FILE__, __LINE__);
    }
    if (pObj->LockedFlag()) {
      // Object already locked
      return true;
    }
    return m_session->TryLockObj(pObj);
  }
  else {
    pObj = this->GetObjFromLiveCacheBase(oid, OMS_Context::TryLock); 
    if (NULL == pObj) {
      m_session->ThrowDBError (e_object_not_found, msg, oid, __MY_FILE__, __LINE__);
    }
    return pObj->LockedFlag();
  }
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::LockResult (tsp00_Int2 DBError, OmsObjectContainerPtr p, const OmsObjectId& oid, const char* msg) 
{
  if (DBError != 0) {
    if (e_object_dirty == DBError) {
      m_session->IncOutOfDate();
      throw OmsOutOfDate(oid, __MY_FILE__, __LINE__);
    }
    else {
      m_session->ThrowDBError (DBError, msg, oid, __MY_FILE__, __LINE__);
    }
    return;
  }
  else {
    if (NULL != p) {
      p->MarkLocked();
    }
    return;
  }
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::LockResult (int cnt, tsp00_Int2* pDBError, OmsObjectContainer** p, const OmsObjectId* pOid, const char* msg) 
{
  int  err   = -1;
  for (int i=0; i<cnt; ++i){
    if (pDBError[i] == 0 && p && p[i]) {
      // Set local lock-flag
      p[i]->MarkLocked();
      m_session->IncLock();
    }
    else if (pDBError[i] != 0){
      // Check error code
      if (e_object_dirty == pDBError[i]) {
        m_session->IncOutOfDate();
        if (err == -1){
          err = i;
        }
      }
      else {
        // Errors, which are not out-of-date, have a higher priority
        err = i;
      }
    }
  }
  // If an error occured thow exception 
  if (err != -1){
    if (pDBError[err] == e_object_dirty) {
      throw OmsOutOfDate(pOid[err], __MY_FILE__, __LINE__);
    }
    else {
      m_session->ThrowDBError (pDBError[err], msg, pOid[err], __MY_FILE__, __LINE__);
    }
  }
}

/*----------------------------------------------------------------------*/

inline bool OMS_Context::TryLockResult (tsp00_Int2 DBError, OmsObjectContainerPtr p, const OmsObjectId& oid, const char* msg) 
{
  if (DBError != 0) {
    if (e_object_dirty == DBError) {
      m_session->IncOutOfDate();
      return false;
    }
    else if (e_request_timeout == DBError) {
      return false;
    }
    else {
      tsp00_Int4  BufLen = sizeof(DBError);
      tsp00_Int2  SqlError;
      // transform basis error into sql return code
      m_session->m_lcSink->MultiPurpose (m_change, mm_nil, &BufLen, 
        (unsigned char*) &DBError, &SqlError);
      if (SqlError == 400 || SqlError == 500) {
        m_session->IncOutOfDate();
        return false;
      }
      m_session->ThrowDBError (DBError, msg, oid, __MY_FILE__, __LINE__);
    }
    return true;
  }
  else {
    if (NULL != p) {
      p->MarkLocked();
    }
    return true;
  }
}

/*----------------------------------------------------------------------*/

inline void* OMS_Context::allocate(size_t sz) 
{
    if (OMS_Globals::m_globalsInstance->IsOmsTestLib())
    {
        OMS_Globals::GetKernelInterface()->TestBadAlloc();
    }
#ifdef USE_SYSTEM_ALLOC_CO13
    return new char[sz];
#else
    return m_heap.Allocate((SAPDB_ULong) sz);
#endif
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::PutObjectIntoContext (OmsObjectContainerPtr p, tsp00_Uint4 ContainerHandle) 
{
  const char* msg = "PutObjectIntoContext";
  
  OMS_ClassIdEntry* pContainerInfo = this->GetContainerInfo(ContainerHandle);

  if (NULL != pContainerInfo) {
    p->SetContainerInfo(pContainerInfo);
    OMS_DETAIL_TRACE(p->IsNewObject() ? (omsTrContext | omsTrNewObj) : omsTrContext, 
      m_session->m_lcSink, "OMS_Context::PutObjectIntoContext : " << p->m_oid
      << ", class: " << p->GetContainerInfo(this)->GetClassInfoPtr()->GetClassName());

    m_oidDir.HashInsert(p);
    if (p->IsVerNewObject()) {
      tsp00_Int4 size = (pContainerInfo->GetObjectSize() + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
      m_newObjCache.registerObject(ContainerHandle, p, (OmsObjectContainer**) (((char*) p) + size));
      p->MarkVerNewRegistered();
    }
  }
  else {
    m_session->ThrowDBError(e_unknown_guid, msg, __MY_FILE__, __LINE__);
  }
}

/*----------------------------------------------------------------------*/

inline bool OMS_Context::PutObjectIntoContextReg (OmsObjectContainerPtr p, tsp00_Uint4 ContainerHandle) 
{
  const char* msg = "PutObjectIntoContextReg";

  try {
    OMS_ClassIdEntry* pContainerInfo = this->GetContainerInfoReg(ContainerHandle);

    if (NULL != pContainerInfo) {
      p->SetContainerInfo(pContainerInfo);
      OMS_DETAIL_TRACE(p->IsNewObject() ? (omsTrContext | omsTrNewObj) : omsTrContext, 
        m_session->m_lcSink, "OMS_Context::PutObjectIntoContext : " << p->m_oid
        << ", class: " << p->GetContainerInfo(this)->GetClassInfoPtr()->GetClassName());

      m_oidDir.HashInsert(p);
      if (p->IsVerNewObject()) {
        tsp00_Int4 size = (pContainerInfo->GetObjectSize() + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
        m_newObjCache.registerObject(ContainerHandle, p, (OmsObjectContainer**) (((char*) p) + size));
        p->MarkVerNewRegistered();
      }
      return true;
    }
    else {
      return false;
    }
  } catch (DbpError &e) {
    // this is for added security, if something throws DbpError
    if (e_unknown_guid == e.dbpError()) {
      DbpErrorCallbackInterface *pCBInterface = DbpError::dbpGetCallback();  // PTS 1127871
      if (pCBInterface){
        pCBInterface->dbpCaughtError(e);
      }
      return false;
    }
    else {
      throw;
    }
  }
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::RenameVersion(const OmsVersionId& OldId, const OmsVersionId& NewId) 
{
  SAPDB_MemCopyNoCheck (m_version, NewId, sizeof(m_version));
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::ResetNewObjectsToFlush()
{
  m_cntNewObjectsToFlush = 0;
}
/*----------------------------------------------------------------------*/

inline void OMS_Context::ResetConsistentView () 
{
  m_consistentView.gg90SetNil();
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::SetConsistentView(const tgg91_TransNo& v) 
{
   m_consistentView = v;
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::SetNext(OMS_Context* pContext)
{
  m_next = pContext;
}

/*----------------------------------------------------------------------*/

inline void OMS_Context::SetNextUnloaded(OMS_Context* pContext)
{
  m_nextUnloaded = pContext;
}

/*----------------------------------------------------------------------*/
// PTS 1117690
inline void OMS_Context::SetVersionDesc(const OmsTypeWyde* desc)
{
  if (m_versionDesc != NULL){
    deallocate(m_versionDesc);
    m_versionDesc = NULL;
  }

  if (desc == NULL){
    return;
  }

  // Get length of desciption
  int len = 0;
  while (desc[len] != 0 && len < OMS_MAX_VERSION_DESC_LENGTH){
    ++len;
  }

  // Allocate memory and copy description.
  // Every desciption longer than MAX_... will be truncated.
  // Memory will be freed in destructor of omsContext_co12.
  m_versionDesc = reinterpret_cast<OmsTypeWyde*>(allocate((len + 1) * sizeof(OmsTypeWyde)));
  SAPDB_MemCopyNoCheck(m_versionDesc, desc, len * sizeof(OmsTypeWyde));
  m_versionDesc[len] = 0;  // ensure that string in null-terminated
}

/*----------------------------------------------------------------------*/

void OMS_Context::RemoveUnlockedObjFromCache() 
{
  m_oidDir.RemoveUnlockedObjFromCache();
}

/*----------------------------------------------------------------------*/

inline unsigned char*  OMS_Context::VersionContext() 
{
  return REINTERPRET_CAST(unsigned char*, m_pVersionContext);
}

/*----------------------------------------------------------------------*/

// PTS 1127648
//inline OmsObjectId OMS_Context::VersionNewOid()
//{
//  OmsObjectId oid;
//  oid.setPno(OMS_VERSION_OBJ_PAGE_NO);
//  IncVersionKey();
//  tgg92_OmsTypeOid* pOid = REINTERPRET_CAST(tgg92_OmsTypeOid*, &oid);
//  pOid->generation = CurrentVersionKey() / (256 * 256);  
//  pOid->pagePos    = CurrentVersionKey() % (256 * 256);
//  return oid;
//}

/*----------------------------------------------------------------------*/

inline void* OMS_Context::operator new(size_t sz)
{
  return OMS_Globals::m_sharedMemAllocatorInstance.allocate(sz);
}

/*----------------------------------------------------------------------*/

// PTS 1125361
inline OmsObjectContainer* OMS_Context::ReactivateReplacedVersion(OmsObjectContainer* p)
{
  return m_oidDir.ReactivateReplacedVersion(p);
}

/*----------------------------------------------------------------------*/
#if defined(OMS_PLACEMENT_DELETE)
inline void OMS_Context::operator delete (void* p)
{
  REINTERPRET_CAST(OMS_Context*, p)->DeleteSelf();
}
#endif

#endif // __OMS_CONTEXT_HPP
