/*!
 * \file    OMS_Handle.cpp
 * \author  IvanS, MarkusS, PeterG
 * \brief   OMS handle implementation
 */
/*

    ========== 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



*/

#include "Oms/OMS_Handle.hpp"
#include "Oms/OMS_Globals.hpp"
#include "Oms/OMS_Session.hpp"
#include "Oms/OMS_CallbackInterface.hpp"
#include "Oms/OMS_VersionDictionary.hpp"
#include "Oms/OMS_ContainerDictionary.hpp"
#include "Oms/OMS_MonitorDirectory.hpp"
#include "Oms/OMS_OidArrayReader.hpp"
#include "Oms/OMS_OidArrayWriter.hpp"
#include "Oms/OMS_ObjectContainer.hpp"
#include "Oms/OMS_VarOid.hpp"
#include "Oms/OMS_COMMonitor.hpp"
#include "Oms/OMS_Defines.h"
#include "liveCache/LVC_IliveCacheSink.hpp"
#include "SAPDBCommon/SAPDB_UTF8Basis.hpp"
#include "SAPDBCommon/SAPDB_MemCopyMove.hpp"
#include "hsp77.h"
#include "hsp78_0.h"
#include "ggg200.h"
#include "geo573.h"
#include "Oms/OMS_VarObjByClsIter.hpp"

static inline OmsObjectContainerPtr omsGetContainer(const OmsAbstractObject* pObj)
{
  if (NULL == pObj) throw DbpError (DbpError::RTE_ERROR, e_nil_pointer, __MY_FILE__, __LINE__);
  return (OmsObjectContainerPtr) ((unsigned char*) pObj - OmsObjectContainer::headerSize());
}

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

inline void OmsHandle::omsIfNilOidThrowError(OmsHandle* h, const OmsObjectId& oid, const char* method) 
{
  if (!oid) {
    h->m_pSession->ThrowDBError (e_nil_pointer, method, __MY_FILE__, __LINE__); 
  }
}

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

//#if defined(WIN32)
///*int omsDebugEvalException (OmsHandle* pHandle, LPEXCEPTION_POINTERS lpexceptInfo); PTS 1106505 FF */
///*int omsDebugEvalException (IliveCacheSink* m_sysLcSink, LPEXCEPTION_POINTERS lpexceptInfo );PTS 1110787 FF */
//static int omsDebugEvalException (OMS_Session* omsSession, LPEXCEPTION_POINTERS lpexceptInfo ) /* PTS 1110787 FF*/
//{
//
//#define STATUS_UNHANDLED_CPP_EXCEPTION (unsigned long)0xE06D7363L   
//  int  ret = EXCEPTION_EXECUTE_HANDLER; 
//  /* char cExceptCode[32]; PTS 1110787 FF */
//  switch (lpexceptInfo->ExceptionRecord->ExceptionCode)
//  {
//    /* PTS 1110787 FF
//
//    case STATUS_WAIT_0:                       // 0x00000000L    
//    strcpy(cExceptCode,"WAIT_0"); break;
//    case STATUS_ABANDONED_WAIT_0:             // 0x00000080L    
//    strcpy(cExceptCode,"ABANDONED_WAIT_0"); break;
//    case STATUS_USER_APC:                     // 0x000000C0L    
//    strcpy(cExceptCode,"USER_APC"); break;
//    case STATUS_TIMEOUT:                      // 0x00000102L    
//    strcpy(cExceptCode,"TIMEOUT"); break;
//    case STATUS_PENDING:                      // 0x00000103L    
//    strcpy(cExceptCode,"PENDING"); break;
//    case STATUS_SEGMENT_NOTIFICATION:         // 0x40000005L    
//    strcpy(cExceptCode,"SEGMENT_NOTIFICATION"); break;
//    case STATUS_GUARD_PAGE_VIOLATION:         // 0x80000001L    
//    strcpy(cExceptCode,"GUARD_PAGE_VIOLATION"); break;
//    case STATUS_NONCONTINUABLE_EXCEPTION:     // 0xC0000025L    
//    strcpy(cExceptCode,"GUARD_PAGE_VIOLATION"); break;
//    case STATUS_BREAKPOINT:                   // 0x80000003L
//    return EXCEPTION_CONTINUE_SEARCH;
//    case STATUS_SINGLE_STEP:                  // 0x80000004L    
//    strcpy(cExceptCode,"SINGLE_STEP"); break;
//    case STATUS_IN_PAGE_ERROR:                // 0xC0000006L    
//    strcpy(cExceptCode,"IN_PAGE_ERROR"); break;
//    case STATUS_ILLEGAL_INSTRUCTION:          // 0xC000001DL    
//    strcpy(cExceptCode,"ILLEGAL_INSTRUCTION"); break;
//    case STATUS_PRIVILEGED_INSTRUCTION:       // 0xC0000096L    
//    strcpy(cExceptCode,"PRIVILEGED_INSTRUCTION"); break;
//    case STATUS_STACK_OVERFLOW:               // 0xC00000FDL    
//    strcpy(cExceptCode,"STACK_OVERFLOW"); break;
//    case STATUS_CONTROL_C_EXIT:               // 0xC000013AL    
//    strcpy(cExceptCode,"CONTROL_C_EXIT"); break;
//    case STATUS_DATATYPE_MISALIGNMENT:        // 0x80000002L   
//    strcpy(cExceptCode,"DATATYPE_MISALIGNMENT"); break;
//    case STATUS_ACCESS_VIOLATION:             // 0xC0000005L    
//    strcpy(cExceptCode,"ACCESS_VIOLATION"); break;
//    case STATUS_INVALID_HANDLE:               // 0xC0000008L    
//    strcpy(cExceptCode,"INVALID_HANDLE"); break;
//    case STATUS_NO_MEMORY:                    // 0xC0000017L    
//    strcpy(cExceptCode,"NO_MEMORY"); break;
//    case STATUS_INVALID_DISPOSITION:          // 0xC0000026L    
//    strcpy(cExceptCode,"INVALID_DISPOSITION"); break;
//    case STATUS_ARRAY_BOUNDS_EXCEEDED:        // 0xC000008CL    
//    strcpy(cExceptCode,"ARRAY_BOUNDS_EXCEEDED"); break;
//    case STATUS_FLOAT_DENORMAL_OPERAND:       // 0xC000008DL    
//    strcpy(cExceptCode,"FLOAT_DENORMAL_OPERAND"); break;
//    case STATUS_FLOAT_DIVIDE_BY_ZERO:         // 0xC000008EL    
//    strcpy(cExceptCode,"FLOAT_DIVIDE_BY_ZERO"); break;
//    case STATUS_FLOAT_INEXACT_RESULT:         // 0xC000008FL    
//    strcpy(cExceptCode,"FLOAT_INEXACT_RESULT"); break;
//    case STATUS_FLOAT_INVALID_OPERATION:      // 0xC0000090L    
//    strcpy(cExceptCode,"FLOAT_INVALID_OPERATION"); break;
//    case STATUS_FLOAT_OVERFLOW:               // 0xC0000091L    
//    strcpy(cExceptCode,"FLOAT_OVERFLOW"); break;
//    case STATUS_FLOAT_STACK_CHECK:            // 0xC0000092L    
//    strcpy(cExceptCode,"FLOAT_STACK_CHECK"); break;
//    case STATUS_FLOAT_UNDERFLOW:              // 0xC0000093L    
//    strcpy(cExceptCode,"FLOAT_UNDERFLOW"); break;
//    case STATUS_INTEGER_DIVIDE_BY_ZERO:       // 0xC0000094L    
//    strcpy(cExceptCode,"INTEGER_DIVIDE_BY_ZERO"); break;
//    case STATUS_INTEGER_OVERFLOW:             // 0xC0000095L    
//    strcpy(cExceptCode,"INTEGER_OVERFLOW"); break;
//    case STATUS_UNHANDLED_CPP_EXCEPTION:      // 0xE06D7363L   
//    strcpy(cExceptCode,"UNHANDLED_C++_EXCEPTION"); break;  
//    default:
//    sprintf(cExceptCode,"ExceptionCode: 0x%8.8X ", 
//    lpexceptInfo->ExceptionRecord->ExceptionCode);
//    ret = EXCEPTION_CONTINUE_SEARCH;
//    */
//    /* ++++++  PTS 1110787 ++++++ */
//  case STATUS_FLOAT_DIVIDE_BY_ZERO:         // 0xC000008EL    
//  case STATUS_FLOAT_INEXACT_RESULT:         // 0xC000008FL    
//  case STATUS_FLOAT_OVERFLOW:               // 0xC0000091L    
//  case STATUS_FLOAT_UNDERFLOW:              // 0xC0000093L    
//  case STATUS_INTEGER_DIVIDE_BY_ZERO:       // 0xC0000094L    
//  case STATUS_INTEGER_OVERFLOW:             // 0xC0000095L    
//  case STATUS_UNHANDLED_CPP_EXCEPTION:      // 0xE06D7363L   
//    ret = EXCEPTION_EXECUTE_HANDLER;                
//    break;  
//  default:
//    ret = EXCEPTION_CONTINUE_SEARCH;                
//    break;
//    /* ------  PTS 1110787 ------ */
//  }
//  //  pHandle->dbpOpError("%s at address 0x%8.8X", cExceptCode,   PTS 1106505 FF
//  //    lpexceptInfo->ExceptionRecord-> ExceptionAddress);        PTS 1106505 FF
//  if ( ret == EXCEPTION_EXECUTE_HANDLER )                    /* PTS 1110787 FF */
//  {                                                          /* PTS 1110787 FF */
//    __try                                                    /* PTS 1110787 FF */
//    {                                                        /* PTS 1110787 FF */
//      /* PTS 1106505 FF +++++++++++++++++++++  */
//      tsp00_Int2  DummyError;
//      tsp00_Int4  BufLen = sizeof(tsp00_Addr);
//      tsp00_Addr  Buf = REINTERPRET_CAST(tsp00_Addr,lpexceptInfo);
//      IliveCacheSink* m_sysLcSink = omsSession->m_lcSink;      /* PTS 1110787 FF */
//      OMS_HResult hr = m_sysLcSink->MultiPurpose (m_diagnose, mm_dump, &BufLen, 
//        (unsigned char*) &Buf, &DummyError);
//      /* PTS 1106505 FF ---------------------  */
//      /* PTS 1106505 FF ---------------------  */
//    }                                                         /* PTS 1110787 FF */
//    __except (EXCEPTION_EXECUTE_HANDLER)                      /* PTS 1110787 FF */
//    {                                                         /* PTS 1110787 FF */
//      ret = EXCEPTION_CONTINUE_SEARCH;                        /* PTS 1110787 FF */
//    }                                                         /* PTS 1110787 FF */
//  }                                                           /* PTS 1110787 FF */
//  return ret;
//}
//#endif

/*----------------------------------------------------------------------*/ 
/* Implementation of class OmsHandle                                    */
/*----------------------------------------------------------------------*/ 

OmsHandle::OmsHandle (OmsTypeInt4 sz)
  : m_session(NULL)   
  , m_pSession(NULL)
  , m_monitor(NULL)
  , m_dummyCancelFlag(false) // PTS 1110812
  , m_pCancelFlag(&m_dummyCancelFlag)  
{
}

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

HRESULT OmsHandle::omsAttachDefaultContext()
{
  pasbool*     pToCancel;
  tsp00_TaskId taskId;
  HRESULT hr = (*m_session)->GetDefaultContext(REINTERPRET_CAST(void**, &m_pSession),  
    &pToCancel, taskId);
  if ((!FAILED(hr)) && (NULL == m_pSession)) {
    m_pSession = new OMS_Session(*m_session, OMS_Globals::KernelInterfaceInstance->GetOmsRegionCnt(), pToCancel, taskId); /* PTS 1107849 */
    if (NULL == m_pSession) {
      return E_OUTOFMEMORY;
    }
    m_pCancelFlag = pToCancel;
    try {
       m_pSession->CreateDefaultContext();
    }
    catch (DbpError &e) {
      DbpErrorCallbackInterface *pCBInterface = DbpError::dbpGetCallback();  // PTS 1127871
      if (pCBInterface){
        pCBInterface->dbpCaughtError(e);
      }

      OMS_TRACE(omsTrSession, (*m_session), "create session failed : out of memory");
      m_pSession->IncRefCnt();
      m_pSession->DeleteSession();
      return E_OUTOFMEMORY;
    }
    hr = (*m_session)->SetDefaultContext((void*) m_pSession);
    OMS_TRACE(omsTrSession, (*m_session), "New Session : " << m_pSession); 
  }
  // PTS 1116693
  // Insert actual OmsHandle into the HandleList of the SessionContext
  // Needed for omsGetOmsHandle
  m_pSession->m_handleList.push_back (this);

  dbpAdviseLcSink(*m_session);
  m_pSession->IncRefCnt();
  OMS_TRACE(omsTrSession, (*m_session), "Session " << m_pSession << " attached to Hndl " << this << " RefCnt " << m_pSession->m_refCnt);
  return hr;
}

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

OMS_ClassIdEntry* OmsHandle::omsAddContainerInfo (OMS_ContainerInfo* ContainerInfo)
{
  OMS_ClassIdEntry* curr = new(m_pSession->m_context) OMS_ClassIdEntry (ContainerInfo, m_pSession->m_context);
  m_pSession->AddContainerInfo (curr);
  return curr;
}

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

OmsObjByClsIterBase OmsHandle::omsAllOids( const ClassIDRef guid, OmsSchemaHandle Schema, OmsContainerNo ContainerNo, int maxBufferSize) 
{
  _TRACE_METHOD_ENTRY(this,"omsAllOids");
  OMS_CHECK_EXCEPTION(*this);

  
  OmsObjByClsIterBase iterator(m_pSession,
                               m_pSession->GetClsInfo(guid, Schema, ContainerNo),
                               maxBufferSize);
  return iterator;
}

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

OmsVarObjByClsIter OmsHandle::omsAllVarOids(OmsSchemaHandle Schema, OmsContainerNo ContainerNo, int maxBufferSize) 
{
  _TRACE_METHOD_ENTRY(this,"omsAllVarOids");
  OMS_CHECK_EXCEPTION(*this);

  m_pSession->RegVarObjectContainer (Schema, ContainerNo);

  OmsVarObjByClsIter iterator(m_pSession,
                              m_pSession->GetClsInfo(OMS_VAR_OBJ_GUID, Schema, ContainerNo),
                              maxBufferSize);
  return iterator;
}

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

void OmsHandle::omsCancel() /* PTS 1113128 */
{
  *m_pCancelFlag = true;
}

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

bool OmsHandle::omsCancel(bool toCancel) /* PTS 1118194 */
{
	bool cancelFlag = *m_pCancelFlag != 0;
    *m_pCancelFlag  = toCancel;
	return cancelFlag;
}

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

const OmsObjectId &OmsHandle::omsCastOid(const ClassIDRef guid, const OmsObjectId& oid)
{
  OMS_CHECK_EXCEPTION(*this);
  return m_pSession->CastOid(guid, oid);
}

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

bool OmsHandle::omsCheckOid ( const OmsObjectId& oid, const ClassIDRef guid)
{
  OMS_TRACE(omsTrInterface, m_pSession->m_lcSink, "omsCheckOid : " << guid << "," << oid);
  OMS_CHECK_EXCEPTION(*this);
  return m_pSession->CurrentContext()->CheckOid(oid, guid);
}

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

bool OmsHandle::omsCheckOid (const OmsVarOid& oid)
{
  OMS_TRACE(omsTrInterface, m_pSession->m_lcSink, "omsCheckOid : " << oid);
  OMS_CHECK_EXCEPTION(*this);
  return m_pSession->CurrentContext()->CheckOid(oid);
}

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

void OmsHandle::omsCloseVersion ( const OmsVersionId& versionId )
{
  OMS_CHECK_EXCEPTION(*this);
  tsp00_Int2 DBError;
  if (!m_pSession->InVersion()) {
    return;
  }
  OMS_Context* pVersion = m_pSession->m_context;
  if (pVersion->IsOpenVersion(versionId)) {
    OMS_TRACE(omsTrInterface, m_pSession->m_lcSink, "omsCloseVersion : " << OMS_CharBuffer(versionId, sizeof(versionId)));
    
    if (1 < m_pSession->CurrentSubtransLevel()) {
      m_pSession->ThrowDBError (e_not_implemented, "Open Subtrans", versionId, __MY_FILE__, __LINE__);
    }
//// PTS 1106619
//// PTS 1109449
//#if ( defined (AIX) && (__IBMCPP__ >= 500) )
//    OmsVersionId LocalVersionID ;
//    SAPDB_MemCopyNoCheck(LocalVersionID, versionId, sizeof(OmsVersionId) );
//    OMS_HResult hr = (*m_session)->CloseVersion (&LocalVersionID, &DBError);  
//#else
//    OMS_HResult hr = (*m_session)->CloseVersion (CONST_CAST(OmsVersionId*, &versionId),
//      &DBError);  
//#endif
    OMS_HResult hr = (*m_session)->CloseVersion (&DBError);  

    if ( DBError != 0 ) {
      m_pSession->ThrowDBError (DBError, "omsCloseVersion", versionId, __MY_FILE__, __LINE__);
    }

    bool isDropped = false;
    { // Begin of exclusive critical section.    // PTS 1124533
      ExclusiveVersionDirRgn rgn(OMS_Globals::m_globalsInstance->m_versionDictionary.GetSingleLockId(versionId),
                                 OMS_Globals::m_globalsInstance->m_versionDictionary.UseRWLocks());
      
      m_pSession->CloseVersion();

      if (pVersion->IsDropped()) {
        isDropped = true;
      }
    } // End of exclusive critical section.

    if (isDropped){
      // version has been marked as to be deleted, do it now
      try {
        omsForceDropVersion(versionId);
      }
      catch (DbpError &e) {
        DbpErrorCallbackInterface *pCBInterface = DbpError::dbpGetCallback();  // PTS 1127871
        if (pCBInterface){
          pCBInterface->dbpCaughtError(e);
        }
      }
    }
  }
}

/*----------------------------------------------------------------------*/
/* PTS 1107849 */

void OmsHandle::omsReschedule() const
{
  OMS_CHECK_EXCEPTION(*this);
  m_pSession->Reschedule();
}

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

short OmsHandle::omsCommitHandling (int& phase)
{
  tsp00_Uint4            listCount  = 0;
  tsp00_Uint4            entryCount = 0;
  bool                   inVersion  = m_pSession->InVersion();
  try {
    // no application wanted exceptions in the course of transaction end
    this->omsControlCancelFlag(-1);
    this->omsControlDbpException(-1);
    OmsCallbackInterface* callbackInterface = m_pSession->GetCallbackInterface();
    if (NULL != callbackInterface) {
      callbackInterface->omsValidate (*this, OmsCallbackInterface::BeforeCommit,
        inVersion);
    }
    phase = 0;
    if (OMS_Globals::m_globalsInstance->InSimulator()) {
      // check for not stored, changed objects in simulator
      m_pSession->m_beforeImages.checkStores();
    }
    phase = 1;
    m_pSession->ExecuteSubtransCommit (1);
    phase = 2;
    m_pSession->m_defaultContext->FlushObjCache(false);
    if (m_pSession->InVersion() && !m_pSession->m_context->IsUnloaded())  // PTS 1122280
      m_pSession->m_context->FlushVersionObjCache();                      // PTS 1122280
    phase = 3;
    m_pSession->FreeBeforeImages();
    phase = 4;
    m_pSession->ClearDefaultContext();
    phase = 5;
    if (NULL != callbackInterface) {
      bool read_only          = m_pSession->ForceReadOnly();
      callbackInterface->omsInvalidate (*this, OmsCallbackInterface::AfterCommit,
        m_pSession->InVersion());
      m_pSession->m_lcSink->UserAllocatorCtl(OmsCallbackInterface::BlockTransaction, NULL);  // check TX allocator empty
      m_pSession->UnforceReadOnly(read_only);
      m_pSession->ClearDefaultContext();
    }
    phase = 6;
    m_pSession->TransEnd();
    phase = 7;
    if (inVersion)
    {
      this->CheckHeapThresholds(); /* PTS 1110149 */
    }
  }
  catch (DbpError& e) {
    DbpErrorCallbackInterface *pCBInterface = DbpError::dbpGetCallback();  // PTS 1127871
    if (pCBInterface){
      pCBInterface->dbpCaughtError(e);
    }

    char buf[256];
    sp77sprintf(buf, sizeof(buf), "omsCommit (%d): DbpError %d (%s)", phase, e.dbpError(), e.m_errorText);
    dbpOpError (buf);
    TraceCommitPhase(phase);
    omsRollback(false, false);
    return e_work_rolled_back;
  }
  return 0;
}

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

void OmsHandle::omsControlCancelFlag(int countDown)     // PTS 1112358
{
#if defined(OMSTST)
  m_pSession->SetCancelCountDown(countDown);
#endif
}

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

void OmsHandle::omsControlDbpException(int countDown)   // PTS 1112358
{
#if defined(OMSTST)
  m_pSession->SetExceptionCountDown(countDown);
#endif
}

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

void OmsHandle::omsControlBadAllocExceptions(int countDown)  // PTS 1112358
{
#if defined(OMSTST)
  tsp00_Int2  DummyError;
  tsp00_Int4  BufLen = 0;
  tsp00_Int4    Buf = countDown;
  (*m_session)->MultiPurpose (m_diagnose, mm_down, &BufLen, 
    (unsigned char*) &Buf, &DummyError);
#endif
}

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

void  OmsHandle::TraceCommitPhase(int phase)
{
  char msg[30];
  switch (phase) {
  case 0 :
    strcpy (msg, "omsValidate");
    break;
  case 1 :
    strcpy (msg, "SubtransCommit");
    break;
  case 2 :
    strcpy (msg, "FlushObjCache");
    break;
  case 3 :
    strcpy (msg, "FreeBeforeImages");
    break;
  case 4 :
    strcpy (msg, "ClearDefaultContext");
    break;
  case 5 :
    strcpy (msg, "OmsInvalidate");
    break;
  case 6 :
    strcpy (msg, "TransEnd");
    break;
  default :
    strcpy(msg, "After TransEnd");
  }
  dbpTrace("Commit Phase : %s", msg);
}

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

short OmsHandle::omsCommit (bool doRelease) 
{
  
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsCommit");
  short  e;
  int    phase = 0;
  try {
    e = omsCommitHandling(phase);
    if (0 != e) {
      return e;
    }
  }
  catch (DbpError &e){   // PTS 1127871
    DbpErrorCallbackInterface *pCBInterface = DbpError::dbpGetCallback();  
    if (pCBInterface){
      pCBInterface->dbpCaughtError(e);
    }
    dbpOpError ("omsCommit : DbpError: %d in phase %d (%s)", e.dbpDBError(), phase, e.m_errorText);
    TraceCommitPhase(phase);
    omsRollback(false, false);
    return e_work_rolled_back;
  }
  catch (BAD_ALLOC_GEO573&) { // PTS 1127871
    DbpErrorCallbackInterface *pCBInterface = DbpError::dbpGetCallback();  
    if (pCBInterface){
      pCBInterface->dbpCaughtBadAlloc();
    }
    dbpOpError ("omsCommit : Bad-Alloc in phase %d", phase);
    TraceCommitPhase(phase);
    omsRollback(false, false);
    return e_work_rolled_back;
  }
  catch (...) {
    dbpOpError ("omsCommit : unknown exception");
    TraceCommitPhase(phase);
    omsRollback(false, false);
    return e_work_rolled_back;
  }
  if (doRelease) {
    this->SessionEnd(); /* PTS 1107209 */
  }
  return 0;
}

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

OmsObjByKeyIterBase OmsHandle::omsCreateKeyRangeIter(
  const ClassIDRef guid,
  OmsSchemaHandle  Schema, 
  OmsContainerNo   ContainerNo,
  const void*      pStartKey,      
  const void*      pLowerKey,      // PTS 1119480
  const void*      pUpperKey,
  OmsIterDirection direction,      // PTS 1119480
  int              maxBufferSize)  // PTS 1119480
{
  OMS_CHECK_EXCEPTION(*this);
  OmsObjByKeyIterBase iterator(*this, guid, Schema, ContainerNo, 
                               pStartKey, pLowerKey, pUpperKey,
                               direction, maxBufferSize);
  return iterator;   
}

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

void OmsHandle::IdentifierToWyde(const char* pSource, OmsTypeWyde* pDest) const
{
  pDest[OMS_MAX_SCHEMA_NAME_LENGTH] = 0;
  for (int ix = 0; ix < OMS_MAX_SCHEMA_NAME_LENGTH; ++ix)
  {
    *pDest = *pSource;
    if (0 == *pSource)
    {
      break;
    }
    ++pSource;
    ++pDest;
  }
}

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

void OmsHandle::CheckHeapThresholds() /* PTS 1110149 */
{
  bool forceUnload = false;
  if ((OMS_Globals::KernelInterfaceInstance->HeapThresholdReached())
    ||
    (m_pSession->m_context->HeapUsed() > (tsp00_8ByteCounter) (OMS_Globals::m_globalsInstance->GetOmsVersionThreshold() * 1024))
    ||
    forceUnload)
  {
    m_pSession->m_context->ReduceHeapUsage();
  }
}

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

void OmsHandle::SessionEnd()
{
    /* PTS 1107209 */
    if (m_pSession->InVersion()) {
        OMS_Context* pContext = m_pSession->CurrentContext();
        m_pSession->CloseVersion();
        if (pContext->IsDropped()) {
            omsForceDropVersion(pContext->GetVersionId());
        }
        else
        {
            pContext->MarkNotBoundToTrans(true);
        }
    }
    m_pSession->ClearDefaultContext();
    m_pSession->ReleaseCallbackInterface();

    m_pSession->m_lcSink->UserAllocatorCtl(OmsCallbackInterface::BlockUnregister, NULL);
    m_pSession->m_lcSink->UserAllocatorCtl(OmsCallbackInterface::BlockSession, NULL);
}

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

void OmsHandle::WydeToChar(const OmsTypeWyde* pSource, char* pDest, int destSize, const char* errorMsg) const
{
  int ix = -1;
  do
  {
    ++ix;
    if (pSource[ix] > 255)
    {
      m_pSession->ThrowDBError (e_not_translatable, errorMsg, __MY_FILE__, __LINE__);
    }
    if (ix == destSize)
    {
      m_pSession->ThrowDBError (e_buffer_too_small, errorMsg, __MY_FILE__, __LINE__);
    }
    pDest[ix] = (char) pSource[ix];
  }
  while (0 != pSource[ix]);
}

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

void OmsHandle::omsCommitSubtrans( int required_lvl ) {
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsCommitSubtrans : reqlvl = " << required_lvl);
  OMS_CHECK_EXCEPTION(*this);
  m_pSession->CommitSubtrans(required_lvl);
}

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

void OmsHandle::omsCleanUpAfterCrash() 
{
  const unsigned int MAX_BUFFER_SIZE = 100;
  int                cnt = 0;
  OMS_Context       *ppContext[MAX_BUFFER_SIZE];
 
  OMS_VersionDictionary::Iter iter(OMS_LOCK_EXCLUSIVE);
  while (true){
    OMS_Context *pContext = iter.GetFirstInSlot();  // Exclusive Lock is aquired
    if (pContext == NULL) 
      break;
 
    while (pContext){
      OMS_Context *pNext = iter.GetNextInSlot();
      if ((pContext->IsBoundToTrans()) && (m_pSession->VersionBoundByMe(pContext))) {
        OMS_TRACE (omsTrAlways, m_pSession->m_lcSink, "Implicit Drop Version : " << 
           OMS_CharBuffer(pContext->GetVersionId(), sizeof(pContext->GetVersionId())));
        m_pSession->DropVersionProlog(pContext);
        OMS_Globals::m_globalsInstance->m_versionDictionary.MarkNotUnloadable(m_pSession->m_lcSink, pContext);
        OMS_Globals::m_globalsInstance->m_versionDictionary.DropVersion(pContext->GetVersionId()); 
        if (cnt < MAX_BUFFER_SIZE){
          // Remember a pointer to the context for later destruction. As the version is
          // not registered any more in the version directory, nobody else can change
          // the pointer.
          ppContext[cnt++] = pContext;
        }
        else {
          // To prevent lock contention problems this should never occur. Normally the
          // destruction of the version should be done outside the exclusive region.
          // But if it occurs inside, then 'only' performance will degrade.
          m_pSession->DropVersionEpilog(pContext);
        }
      }
      pContext = pNext;
    }  
    iter.ReleaseSlot();  // Exclusive Lock is freed
 
    for (int i=0; i<cnt; ++i){
      // Destruct the version outside the exclusive region
      m_pSession->DropVersionEpilog(ppContext[i]);
    }
    cnt = 0;
  }
 
  omsRollback(true, true);
}

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

OmsSchemaHandle OmsHandle::omsCreateSchema(const char* SchemaName)
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsCreateSchema : " << SchemaName);
  OmsTypeWyde SchemaNameWyde[OMS_MAX_SCHEMA_NAME_LENGTH + 1];
  this->IdentifierToWyde(SchemaName, &SchemaNameWyde[0]);
  return omsCreateSchema(&SchemaNameWyde[0]);
}

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

OmsSchemaHandle OmsHandle::omsCreateSchema(const OmsTypeWyde* SchemaName) 
{
  OMS_CHECK_EXCEPTION(*this);
  int length = 0;
  while (SchemaName[length] != 0)
  {
    ++length;
  }
  if (length > OMS_MAX_SCHEMA_NAME_LENGTH)
  {
    CONST_CAST(OmsHandle*, this)->dbpOpError("omsCreateSchema : too long identifier : %d, ", length);
    m_pSession->ThrowDBError (e_identifier_too_long, "omsCreateSchema", __MY_FILE__, __LINE__);
  }
  tsp00_Int4          SchemaId = 0;
  tgg00_BasisError    DBError;

  OMS_HResult hr = (*m_session)->CreateSchema (SchemaName, &SchemaId, &DBError);
  if ( DBError != 0 ) {
    m_pSession->ThrowDBError (DBError, "omsCreateSchema", __MY_FILE__, __LINE__);
  }
  return SchemaId;
}

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

void OmsHandle::omsCreateVersion(const OmsVersionId& versionId)
{
  omsCreateVersion(versionId, reinterpret_cast<OmsTypeWyde*>(NULL));
}

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

void OmsHandle::omsCreateVersion(const OmsVersionId& versionId, const char* desc)
{
  if (desc == NULL){
    omsCreateVersion(versionId, reinterpret_cast<OmsTypeWyde*>(NULL));
  }
  else{
    OmsTypeWyde desc_wyde[OMS_MAX_VERSION_DESC_LENGTH + 1];
    tsp00_Uint4           destBytesWritten;
    tsp00_Uint4           srcBytesParsed;
    tsp78ConversionResult error;
    int len_wyde = (OMS_MAX_VERSION_DESC_LENGTH + 1) * sizeof(OmsTypeWyde);
    
    // truncate input-string if necessary
    int len = strlen(desc);
    if (len > OMS_MAX_VERSION_DESC_LENGTH){
      len = OMS_MAX_VERSION_DESC_LENGTH;
    }

    // Convertion from ASCII to UCS2
    error = sp78convertString(sp77encodingUCS2Native,        // destEndcoding
                              desc_wyde,                     // destBuffer
                              len_wyde,                      // destBufferLengthInBytes
                              &destBytesWritten,             // destBytesWritten
                              true,                          // addZeroTerminator
                              sp77encodingAscii,             // srcEncoding
                              desc,                          // srcBuffer
                              len,                           // srcBufferLengthInBytes
                              &srcBytesParsed);              // srcBytesParsed
        
    if (error != sp78_Ok){
      // Reset array again
      memset(desc_wyde, 0, len_wyde);
    }

    omsCreateVersion(versionId, desc_wyde);
  }
}

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

void OmsHandle::omsCreateVersion( const OmsVersionId& versionId, const OmsTypeWyde* desc )
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsCreateVersion : " << OMS_CharBuffer(versionId, sizeof(versionId)));
  OMS_CHECK_EXCEPTION(*this);
  tsp00_Int2   DBError;
  OMS_Context* initContext = m_pSession->CurrentContext();
  if (m_pSession->IsSubtransOpen()) {
    m_pSession->ThrowDBError (e_too_many_subtrans, "Open Subtrans", versionId, __MY_FILE__, __LINE__);
  }
  if (m_pSession->InVersion()) {
    m_pSession->ThrowDBError (e_already_in_version, "omsCreateVersion", versionId, __MY_FILE__, __LINE__); 
  }
  m_pSession->CreateVersion(versionId, desc);

  { // Begin of exclusive critical section.    // PTS 1124533
    ExclusiveVersionDirRgn rgn(OMS_Globals::m_globalsInstance->m_versionDictionary.GetSingleLockId(versionId),
                               OMS_Globals::m_globalsInstance->m_versionDictionary.UseRWLocks());

    try 
    {
        DBError = OMS_Globals::m_globalsInstance->m_versionDictionary.InsertVersion(versionId, m_pSession->CurrentContext());
    }
    catch (BAD_ALLOC_GEO573&)
    {     
      // Exception is thrown below, therefore no call of callback dbpCaughtError necessary

      DBError = e_no_more_memory;  // Should never happen !
    }
  }  // End of exclusive critical section.

  if (DBError != 0) {
      m_pSession->RemoveFromTransVersion(m_pSession->m_context);
      m_pSession->m_context->DeleteSelf();
      m_pSession->SetContext(initContext);
      if (e_duplicate_key == DBError){
          m_pSession->ThrowDBError (e_duplicate_name, "omsCreateVersion", versionId, __MY_FILE__, __LINE__);
      }
      else {
          m_pSession->ThrowDBError (DBError, "omsCreateVersion", versionId, __MY_FILE__, __LINE__);
      }
  }
}

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

int OmsHandle::omsCurrentSubtransLevel() const
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsCurrentSubtransLevel : " << m_pSession->CurrentSubtransLevel() - 1);
  OMS_CHECK_EXCEPTION(*this);
  return m_pSession->CurrentSubtransLevel() - 1;
}

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

const OmsVersionId*  OmsHandle::omsCurrentVersionId () const
{
  OMS_CHECK_EXCEPTION(*this);
  if (m_pSession->InVersion()) {
    return REINTERPRET_CAST(const OmsVersionId*, &m_pSession->CurrentContext()->GetVersionId()[0]);
  }
  return NULL;
}

/*----------------------------------------------------------------------*/
// PTS 1122839
long OmsHandle::omsGetStoredErrorCode() const
{
  return m_pSession->GetStoredErrorCode();
}

/*----------------------------------------------------------------------*/
// PTS 1117690
bool OmsHandle::omsGetVersionInfo(const OmsVersionId& versionId, 
                                  OmsVersionInfo& info,
                                  char* pDescBuf, 
                                  int bufLen) const
{ 
  if (pDescBuf == NULL || bufLen <= 0){
    return omsGetVersionInfo(versionId, info, reinterpret_cast<OmsTypeWyde*>(NULL), 0);
  }
  else{
    OmsTypeWyde descBuf_wyde[OMS_MAX_VERSION_DESC_LENGTH + 1];  
    
    // PTS 1118474
    if (bufLen > OMS_MAX_VERSION_DESC_LENGTH){
      bufLen = OMS_MAX_VERSION_DESC_LENGTH;
    }

    // PTS 1118592
    // Initialize output-buffer if requested
    memset(pDescBuf, 0, bufLen);

    bool found = omsGetVersionInfo(versionId, info, descBuf_wyde, bufLen);

    if (found && descBuf_wyde[0] != 0){
      tsp00_Uint4 destBytesWritten;
      tsp00_Uint4 srcBytesParsed;
      tsp78ConversionResult error;
      int bufLen_wyde = bufLen * sizeof(OmsTypeWyde);

      // Convertion from UCS2 to ASCII 
      error = sp78convertString(sp77encodingAscii,      // destEndcoding
                                pDescBuf,               // destBuffer
                                bufLen,                 // destBufferLengthInBytes
                                &destBytesWritten,      // destBytesWritten
                                true,                   // addZeroTerminator
                                sp77encodingUCS2Native, // srcEncoding
                                descBuf_wyde,           // srcBuffer
                                bufLen_wyde,            // srcBufferLengthInBytes
                                &srcBytesParsed);       // srcBytesParsed
        
      if (error != sp78_Ok){
        // Reset array again
        memset(pDescBuf, 0, bufLen);
      }
    }

    return found;
  }
}

/*----------------------------------------------------------------------*/
// PTS 1117690
void OmsHandle::CopyVersionInfo (OMS_Context    *pContext, 
                                 OmsVersionInfo &info, 
                                 OmsTypeWyde    *pDescBuf, 
                                 int             bufLen) const
{
  *((tsp00_Date*)&info.createDate)  = pContext->GetCreateDate();
  *((tsp00_Time*)&info.createTime)  = pContext->GetCreateTime();
  *((tsp00_Date*)&info.openDate)    = pContext->GetOpenDate();
  *((tsp00_Time*)&info.openTime)    = pContext->GetOpenTime();
  info.consistentView = pContext->m_consistentView.gg90GetInt4();
  info.isMarked       = pContext->IsMarked();
  info.isOpen         = pContext->IsVersionOpen();
  info.isUnloaded     = pContext->IsUnloaded();
  info.heapUsage      = (OmsTypeInt8)pContext->HeapUsed();
  info.hashSize       = pContext->GetHashSize();

  if (pDescBuf != NULL && bufLen > 0 && pContext->GetVersionDesc() != NULL){
    // truncate desciption string if necessary
    int len = OMS_Globals::WideStrlen(pContext->GetVersionDesc());
    if (bufLen < len + 1){
      len = bufLen - 1;
    }

    // copy desciption
    SAPDB_MemCopyNoCheck(pDescBuf, pContext->GetVersionDesc(), len * sizeof(OmsTypeWyde));
    pDescBuf[len] = 0;  // ensure that string is null-terminated
  }
}

/*----------------------------------------------------------------------*/
// PTS 1117690
bool OmsHandle::omsGetVersionInfo (const OmsVersionId& versionId, 
                                   OmsVersionInfo& info, 
                                   OmsTypeWyde* pDescBuf, 
                                   int bufLen) const
{  
  OMS_CHECK_EXCEPTION(*this);

  if (pDescBuf != NULL && bufLen > 0){
     // Initialize output-buffer if requested
    int bufLen_byte = bufLen * sizeof(OmsTypeWyde);
    memset(pDescBuf, 0, bufLen_byte);
  }

  OMS_Context* pContext = NULL;
  if (m_pSession->InVersion()){
    if (!memcmp(&versionId[0], &(*omsCurrentVersionId())[0], sizeof(OmsVersionId))){
      // ***  Check if information can be read from the version which is currently open  ***
      pContext = m_pSession->CurrentContext();
    }
  }

  if (pContext != NULL){
    CopyVersionInfo(pContext, info, pDescBuf, bufLen);
    return true;
  }
  else {
    // Begin of exclusive critical section.    // PTS 1124533
    ExclusiveVersionDirRgn rgn(OMS_Globals::m_globalsInstance->m_versionDictionary.GetSingleLockId(versionId),
                               OMS_Globals::m_globalsInstance->m_versionDictionary.UseRWLocks());

    pContext = OMS_Globals::m_globalsInstance->m_versionDictionary.FindVersion(versionId);
    if (pContext == NULL){
      // there is no version which matches specified id
      return false;
    }
    else {
      CopyVersionInfo(pContext, info, pDescBuf, bufLen);
      return true;
    }
  }  // End of exclusive critical section.
}

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

void OmsHandle::omsDelete( const OmsObjectId& oid ) 
{
  const char* msg = "omsDelete";

  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, msg << " : " << oid);
  OMS_CHECK_EXCEPTION(*this);
  m_pSession->AssertNotReadOnly(msg);
  m_pSession->IncDelete ();
  OmsObjectContainerPtr found = m_pSession->CurrentContext()->GetObj(oid, false);
  if (!found) 
  {
    m_pSession->ThrowDBError (e_object_not_found, msg, oid, __MY_FILE__, __LINE__);
  }
  if (!found->LockedFlag() && !m_pSession->IsLocked(oid))
  {
    m_pSession->ThrowDBError (e_object_not_locked, msg, oid, __MY_FILE__, __LINE__);
  }
  OmsAbstractObject* pObj = &found->m_pobj; /* PTS 1107093 */

  m_pSession->InsertBeforeImage (found);

  // As the content of the object might get changed in omsCleanup, this method must not
  // be called before creating the before-image.
  pObj->omsCleanUp(*this);

  found->MarkDeleted();
};

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

void OmsHandle::omsDelete( OmsAbstractObject* pobj ) 
{
  omsDelete (omsGetContainer(pobj)->m_oid);
}

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

void OmsHandle::omsDelete( const OmsVarOid& oid )
{
  OMS_TRACE (omsTrInterface | omsTrVarObject, m_pSession->m_lcSink, "omsDelete(Var) : " << oid);
  OMS_CHECK_EXCEPTION(*this);
  if (!m_pSession->IsLocked(oid))
  {
    m_pSession->ThrowDBError (e_object_not_locked, "omsDelete(varobject)", oid, __MY_FILE__, __LINE__);
  }
  m_pSession->DeleteVarObject(oid);
}

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

void OmsHandle::omsDeleteAll (const ClassIDRef guid, OmsSchemaHandle Schema, OmsContainerNo ContainerNo) {
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsDeleteAll : " << guid << ", " 
    << Schema << ", " << ContainerNo);
  OMS_CHECK_EXCEPTION(*this);
  m_pSession->DeleteAll (guid, Schema, ContainerNo);
}

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

const void* OmsHandle::omsDeRef(const OmsVarOid& oid)
{
  omsIfNilOidThrowError (this, oid, "omsDeRef : VarObject");
  OMS_TRACE (omsTrInterface | omsTrVarObject, m_pSession->m_lcSink, "omsDeRef(Var) : " << oid);
  OMS_CHECK_EXCEPTION(*this);
  return m_pSession->DeRefVarObject(oid);
}

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

OmsAbstractObject* OmsHandle::omsDeRef (const OmsObjectId& oid, const ClassIDRef guid, bool forUpd, bool do_lock )
{
  OMS_CHECK_EXCEPTION(*this);
  if (!oid) {
    return NULL;
  }
  else {
    return m_pSession->DeRef (oid, guid, forUpd, do_lock);
  }
};

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

OmsAbstractObject* OmsHandle::omsDeRefKey (unsigned char*  key, 
                                           const ClassIDRef guid, 
                                           bool            forUpd, 
                                           bool            do_lock,
                                           OmsSchemaHandle Schema,
                                           OmsContainerNo  ContainerNo) 
{
  OMS_CHECK_EXCEPTION(*this);
  return m_pSession->DeRefViaKey (key, guid, forUpd, do_lock, Schema, ContainerNo);  
}

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

void OmsHandle::omsDropSchema(OmsSchemaHandle Schema)
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsDropSchema : " << Schema);
  OMS_CHECK_EXCEPTION(*this);
  if (m_pSession->InVersion()) {
    m_pSession->ThrowDBError (e_missing_privilege, "omsDropSchema : not allowed in version", __MY_FILE__, __LINE__);
  }
  if (OMS_DEFAULT_SCHEMA_HANDLE == Schema) {
    m_pSession->ThrowDBError (e_missing_privilege, "omsDropSchema : OMS Schema not allowed", __MY_FILE__, __LINE__);
  }
  tgg00_BasisError DBError = OMS_Globals::m_globalsInstance->m_classDictionary.DropSchema(m_pSession->m_lcSink, Schema);
  
  // Clear Oid-Hash and Container-directory even if an error occurred during the 
  // dropping of the schema.    PTS 1127421
  m_pSession->CleanAfterDropSchema();
  
  if ( 0 != DBError ) {
    m_pSession->ThrowDBError (DBError, "omsDropSchema", __MY_FILE__, __LINE__);
  }
  //m_pSession->CleanAfterDropSchema();  // PTS 1127421
}

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

void OmsHandle::omsDropContainer(const ClassIDRef guid, OmsSchemaHandle Schema, OmsContainerNo ContainerNo,
                                 size_t arrayByteSize)
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsDropContainer : " << guid << ", " << Schema << ", " << ContainerNo );
  OMS_CHECK_EXCEPTION(*this);
  if (m_pSession->InVersion()) {
    m_pSession->ThrowDBError (e_missing_privilege, "omsDropContainer : not allowed in version", __MY_FILE__, __LINE__);
  }
  tgg00_BasisError DBError = OMS_Globals::m_globalsInstance->m_classDictionary.DropContainer(
    m_pSession->m_lcSink, guid, Schema, ContainerNo, arrayByteSize);

  // Clear Oid-Hash and Container-directory even if an error occurred during the 
  // dropping of the schema.    PTS 1127421
  m_pSession->CleanAfterDropSchema();

  if ( 0 != DBError ) {
    m_pSession->ThrowDBError (DBError, "omsDropContainer", __MY_FILE__, __LINE__);
  }
  //m_pSession->CleanAfterDropSchema();  PTS 1127421
}

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

void OmsHandle::omsDropContainer(const ClassIDRef guid, OmsSchemaHandle sh, OmsContainerNo cn)
{
  omsDropContainer(guid, sh, cn, 0);
}

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

void OmsHandle::omsDropVersion( const OmsVersionId& versionId )
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsDropVersion : " << OMS_CharBuffer(versionId, sizeof(versionId)));
  OMS_CHECK_EXCEPTION(*this);
  OMS_Context*   context;
  { // Begin of exclusive critical section.    // PTS 1124533
    ExclusiveVersionDirRgn rgn(OMS_Globals::m_globalsInstance->m_versionDictionary.GetSingleLockId(versionId),
                               OMS_Globals::m_globalsInstance->m_versionDictionary.UseRWLocks());

    context = OMS_Globals::m_globalsInstance->m_versionDictionary.FindVersion(versionId);
    if (NULL == context) {
      m_pSession->ThrowDBError (e_unknown_version, "omsDropVersion", versionId, __MY_FILE__, __LINE__);
    }
    OMS_Globals::m_globalsInstance->m_versionDictionary.MarkNotUnloadable(this->m_pSession->m_lcSink, context);
    m_pSession->DropVersionProlog(context);
    OMS_Globals::m_globalsInstance->m_versionDictionary.DropVersion(versionId);
  }  // End of exclusive critical section.

  m_pSession->DropVersionEpilog(context);
}

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

const char* OmsHandle::omsSimDumpGetHtmlRef(const OmsObjectId &oid)
{
  const char *data;
  m_pSession->m_lcSink->SimCtlGetHTMLRef(*this, oid, &data, 3);
  return data;
}

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

bool OmsHandle::omsExistsContainer(const ClassIDRef guid, OmsSchemaHandle schema, OmsContainerNo cno) // PTS 1110334
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsExistsContainer : " << guid << "," << schema << "," << cno);
  OMS_CHECK_EXCEPTION(*this);
  tgg00_BasisError DBError;
  GUID_TEMP(lguid, guid);
  OMS_HResult hr = (*m_session)->ExistsContainer (schema, lguid, cno , DBError);
  if (0 == DBError)
  {
    return true;
  }
  else
  {
    if (e_sysinfo_not_found !=DBError)
    {
      m_pSession->ThrowDBError (DBError, "omsExistsContainer", __MY_FILE__, __LINE__);
    }
  }
  return false;
}

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

void OmsHandle::omsForceDropVersion( const OmsVersionId& versionId )
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsDropVersion : " << OMS_CharBuffer(versionId, sizeof(versionId)));
  OMS_CHECK_EXCEPTION(*this);
  OMS_Context*   context;

  { // Begin of exclusive critical section.    // PTS 1124533
    ExclusiveVersionDirRgn rgn(OMS_Globals::m_globalsInstance->m_versionDictionary.GetSingleLockId(versionId),
                               OMS_Globals::m_globalsInstance->m_versionDictionary.UseRWLocks());

    context = OMS_Globals::m_globalsInstance->m_versionDictionary.FindVersion(versionId);
    if (NULL == context) {
      m_pSession->ThrowDBError (e_unknown_version, "omsDropVersion", versionId, __MY_FILE__, __LINE__);
    }
    OMS_Globals::m_globalsInstance->m_versionDictionary.MarkNotUnloadable(this->m_pSession->m_lcSink, context);
    try {
      m_pSession->DropVersionProlog(context);
      OMS_Globals::m_globalsInstance->m_versionDictionary.DropVersion(versionId);
    }
    catch (DbpError& e) {
      if (-5001 == e.dbpError()) {
        DbpErrorCallbackInterface *pCBInterface = DbpError::dbpGetCallback();  // PTS 1127871
        if (pCBInterface){
          pCBInterface->dbpCaughtError(e);
        }

        context->MarkDropped();

        return;
      }
      else {
        throw e;
      }
    }
  } // End of exclusive critical section.

  m_pSession->DropVersionEpilog(context);
}
/*----------------------------------------------------------------------*/

void OmsHandle::omsDump ()
{
  m_pSession->CurrentContext()->DumpObjCache(*this);
};

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

void OmsHandle::omsDumpStackTrace()
{
  OMS_Globals::KernelInterfaceInstance->DumpStackTrace();
}

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

unsigned int OmsHandle::omsSaveStackTrace(void **buffer, unsigned int levels)
{
  return OMS_Globals::KernelInterfaceInstance->SaveStackTrace(buffer, levels);
}

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

void OmsHandle::omsEvalStackTrace(void **buffer, unsigned int levels,
  OmsStackTraceCallbackInterface *cb)
{
  OMS_Globals::KernelInterfaceInstance->EvalStackTrace(buffer, levels, cb);
}

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

void OmsHandle::omsSimDump()
{
  tsp00_Int4 BufLen = 1;
  char Buf[1];
  short DummyError = 0;
  OMS_HResult hr = (*m_session)->MultiPurpose (m_describe, 2, &BufLen, 
    (unsigned char*) &Buf, &DummyError);
}

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

void OmsHandle::omsSimDump(bool version)
{
  tsp00_Int4 BufLen = 1;
  char Buf[1];
  short DummyError = 0;
  OMS_HResult hr = (*m_session)->MultiPurpose (m_describe, version ? 1 : 0, &BufLen, 
    (unsigned char*) &Buf, &DummyError);
}

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

void OmsHandle::omsCommit()
{
  tsp00_Int4 BufLen = 1;
  char Buf[1];
  short DummyError = 0;
  OMS_HResult hr = (*m_session)->MultiPurpose (m_commit, mm_nil, &BufLen, 
    (unsigned char*) &Buf, &DummyError);
}

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

void OmsHandle::omsRollback()
{
  tsp00_Int4 BufLen = 1;
  char Buf[1];
  short DummyError = 0;
  OMS_HResult hr = (*m_session)->MultiPurpose (m_rollback, mm_nil, &BufLen, 
    (unsigned char*) &Buf, &DummyError);
}

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

bool OmsHandle::omsExistsVersion( const OmsVersionId& versionId )
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsExistsVersion : " << OMS_CharBuffer(versionId, sizeof(versionId)));
  OMS_CHECK_EXCEPTION(*this);

  bool isDropped = false;
  OMS_Context* pContext = NULL;
  { // Begin of shared critical section.    // PTS 1124533
    SharedVersionDirRgn rgn(OMS_Globals::m_globalsInstance->m_versionDictionary.GetSingleLockId(versionId),
                            OMS_Globals::m_globalsInstance->m_versionDictionary.UseRWLocks());
  
    pContext = OMS_Globals::m_globalsInstance->m_versionDictionary.FindVersion(versionId);
    if ((NULL != pContext) && (pContext->IsDropped())) {  /* PTS 1107209 */ /* PTS 1107277 */
      isDropped = true;
    }
  } // End of shared critical section.

  if (isDropped){ 
    try {
      omsForceDropVersion(versionId);
      pContext = NULL;
    }
    catch(DbpError &e) {
      DbpErrorCallbackInterface *pCBInterface = DbpError::dbpGetCallback();  // PTS 1127871
      if (pCBInterface){
        pCBInterface->dbpCaughtError(e);
      }
    }
  }
  return (pContext != NULL);
}

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

void OmsHandle::omsExceptionHandler(DbpError& e)
{
  m_pSession->CurrentMethodCallEpilog(-1); // PTS 1126796
  OmsTypeUTF8 utf8Buffer[sizeof(e.m_errorText)*2];
  OmsTypeUTF8* pMsgText;
  if (e.m_isWyde)
  {
    
    SAPDB_UTF8Basis::UCS2ConstPointer srcAt;
    SAPDB_UTF8Basis::UTF8Pointer      destAt;
    pMsgText = &utf8Buffer[0];
    register const OmsTypeWyde* pStart = e.dbpErrorTextWyde();
    register const OmsTypeWyde* pEnd   = pStart;
    while (0 != *pEnd)
    {
      ++pEnd;
    }
    if (!OMS_Globals::KernelInterfaceInstance->IsUnicodeInstance())
    {
      int ix = 0;
      do
      {
        if (*pStart > 255)
        {
          dbpOpError ("omsExceptionHandler : msg not translatable");
          utf8Buffer[ix] = 0;
          break;
        }
        utf8Buffer[ix] = (unsigned char) *pStart;
        if (pStart == pEnd)
        {
          break;
        }
        ++pStart;
        ++ix;
       }
      while (true);
    }
    else
    {
      SAPDB_UTF8Basis::ConversionResult res = SAPDB_UTF8Basis::ConvertFromUCS2 (
        (SAPDB_UTF8Basis::UCS2ConstPointer) pStart,
        (SAPDB_UTF8Basis::UCS2ConstPointer) ++pEnd,
        srcAt,
        &utf8Buffer[0],
        &utf8Buffer[sizeof(e.m_errorText)*2],
        destAt);
    }
  }
  else
  {
    pMsgText = (OmsTypeUTF8*) &e.m_errorText[0];
  }
  switch (e.m_errorKind) {
  case DbpError::DB_ERROR :
    {
      omsRaiseError ((short) e.m_errorNo, pMsgText);
      break;
    }
  case DbpError::HRESULT_ERROR :
    {
      (*m_session)->HResultError (e.m_errorNo);
      break;
    }
  case DbpError::RTE_ERROR :
    {
      omsRaiseError ((short) e.m_errorNo, pMsgText);
      break;
    } 
  case DbpError::USER_DEFINED :
    {
      omsRaiseError ((short) e.m_errorNo, pMsgText);
      break;
    } 
  default :
    dbpOpError ("Invalid DbpError, kind = %d, errno = %d", e.m_errorKind, e.m_errorNo);
    throw;
  }
} 

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

OmsContainerNo OmsHandle::omsGetContainerNo(const OmsObjectId& oid)
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsGetContainerNo : " << oid);
  OMS_CHECK_EXCEPTION(*this);
  omsIfNilOidThrowError (this, oid, "omsGetContainerNo");
  OmsObjectContainerPtr pObj = m_pSession->CurrentContext()->GetObj(oid, false);
  if (NULL != pObj) {
    OMS_ClassIdEntry* pContainerInfo = pObj->GetContainerInfo(m_pSession->CurrentContext());
    return pContainerInfo->GetContainerNo();
  }
  else {
    m_pSession->ThrowDBError (e_object_not_found, "omsGetContainerNo", oid, __MY_FILE__, __LINE__);
    return 0;
  }
}

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

void OmsHandle::omsGetMonitorInfo (tgg01_COMMonitorTransferBuf* lpMonInfo)
{
  if (lpMonInfo->ctbDispId_gg00 < 0) {
    // reset statistics
    m_monitor->Reset();
    return;
  }
  while ((lpMonInfo->ctbDispId_gg00 < m_monitor->size()) &&  
    (0 == (*m_monitor)[lpMonInfo->ctbDispId_gg00].m_monInfo.cmiCallCnt_gg00)) {
    ++lpMonInfo->ctbDispId_gg00;
  }
  if (lpMonInfo->ctbDispId_gg00 >= m_monitor->size()) {
    lpMonInfo->ctbDispId_gg00 = -1;
    return;
  }
  SAPDB_MemCopyNoCheck (&lpMonInfo->ctbMonInfo_gg00, 
    &((*m_monitor)[lpMonInfo->ctbDispId_gg00].m_monInfo),
    sizeof (lpMonInfo->ctbMonInfo_gg00));
  if (csp_maxint4 == lpMonInfo->ctbMonInfo_gg00.cmiCounters_gg00[cmiMinWaitNewConsView]) {
    lpMonInfo->ctbMonInfo_gg00.cmiCounters_gg00[cmiMinWaitNewConsView] = 0;
  }
}

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

bool OmsHandle::omsGetMethodCallMonitorInfo (OmsMonitorData& info) const
{
   return m_pSession->GetMethodCallMonitorInfo(info);
}

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

void OmsHandle::omsGetObj(const OmsObjectId& oid, unsigned char* cnsView, int& ObjLen, unsigned char* obj)
// exported for diagnostics only, not included into interface
{
  tgg91_TransNo cView;
  tgg91_TransNo currCView = m_pSession->m_defaultContext->m_consistentView;
  SAPDB_MemCopyNoCheck (&cView, cnsView, sizeof(cView));
  m_pSession->m_defaultContext->SetConsistentView(cView);
  m_pSession->m_defaultContext->SetConsistentView(cView);
  OmsObjectContainerPtr pObj = m_pSession->m_defaultContext->GetObjFromLiveCacheBase(oid, OMS_Context::NoLock);
  if (NULL != pObj) {
    OMS_ClassIdEntry* pContainerInfo = pObj->GetContainerInfo(m_pSession->m_defaultContext);
    ObjLen = pContainerInfo->GetClassInfoPtr()->GetObjectSize() - OmsObjectContainer::headerSize() - sizeof(void*);
    SAPDB_MemCopyNoCheck (obj, &pObj->m_pobj, ObjLen); 
  }
  else {
    ObjLen = 0;
    obj    = NULL;
  }
  m_pSession->m_defaultContext->SetConsistentView(currCView);
}

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

OmsHandle* OmsHandle::omsGetOmsHandle()
{  // PTS 1116693
   OMS_Session *pSession;
   pasbool         *pToCancel;
   tsp00_TaskId    taskId;
  
   IliveCacheSink* pSink = OMS_Globals::GetCurrentLcSink();
   pSink->GetDefaultContext(REINTERPRET_CAST(void**, &pSession), &pToCancel, taskId);
  
   if( pSession == NULL || pSession->m_handleList.empty()) // PTS 1130713
    return NULL;
   else
    return pSession->m_handleList.front();
    
}
 
/*----------------------------------------------------------------------*/

OmsSchemaHandle OmsHandle::omsGetSchemaHandle(const char* SchemaName) const 
{
  OmsTypeWyde SchemaNameWyde[OMS_MAX_SCHEMA_NAME_LENGTH + 1];
  this->IdentifierToWyde(SchemaName, &SchemaNameWyde[0]);
  return omsGetSchemaHandle(&SchemaNameWyde[0]);
}

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

OmsSchemaHandle OmsHandle::omsGetSchemaHandle(const OmsTypeWyde* SchemaName) const 
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsGetSchemaHandle");
  OMS_CHECK_EXCEPTION(*this);
  tsp00_Int4          SchemaId = 0;
  tgg00_BasisError    DBError;
  OMS_HResult hr = (*m_session)->ExistsSchema (SchemaName, &SchemaId, &DBError);
  if (DBError == e_unknown_name){   // PTS 1122931
    DBError = e_unknown_schema;     // PTS 1122931
  }                                 // PTS 1122931
  if ( 0 != DBError ) {
    m_pSession->ThrowDBError (DBError, "omsGetSchemaHandle", __MY_FILE__, __LINE__);
  }
  return SchemaId;
}

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

OmsSchemaHandle OmsHandle::omsGetSchemaHandle(const OmsObjectId& oid)
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsGetSchemaHandle : " << oid);
  OMS_CHECK_EXCEPTION(*this);
  
  omsIfNilOidThrowError (this, oid, "omsGetSchemaHandle");
  OmsObjectContainerPtr pObj = m_pSession->CurrentContext()->GetObj(oid, false);
  if (NULL != pObj) {
    OMS_ClassIdEntry* pContainerInfo = pObj->GetContainerInfo(m_pSession->CurrentContext());
    return pContainerInfo->GetSchema();
  }
  else {
    m_pSession->ThrowDBError (e_object_not_found, "omsGetSchemaHandle", oid, __MY_FILE__, __LINE__);
    return 0;
  }
}

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

void OmsHandle::omsGetSchemaName(OmsSchemaHandle Schema, char* SchemaName, int SchemaNameBufSize) const 
{
  const char* msg = "omsGetSchemaName";

  OmsTypeWyde SchemaNameWyde[OMS_MAX_SCHEMA_NAME_LENGTH + 1];
  this->omsGetSchemaName(Schema, &SchemaNameWyde[0], OMS_MAX_SCHEMA_NAME_LENGTH + 1);
  this->WydeToChar(&SchemaNameWyde[0], SchemaName, SchemaNameBufSize, msg);
}

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

void OmsHandle::omsGetSchemaName(OmsSchemaHandle Schema, OmsTypeWyde* SchemaName, int SchemaNameBufSize) const 
{
  OMS_CHECK_EXCEPTION(*this);
  OmsTypeWyde SchemaNameWyde[OMS_MAX_SCHEMA_NAME_LENGTH + 1];
  tgg00_BasisError    DBError;
  OMS_HResult hr = m_pSession->m_lcSink->GetSchemaName(Schema, &SchemaNameWyde[0], &DBError);
  if (0 != DBError)
  {
    DbpBase base(m_pSession->m_lcSink);
    base.dbpOpError("omsGetSchemaName : unknown schema handle %d", Schema);
    m_pSession->ThrowDBError (DBError, "omsGetSchemaName", __MY_FILE__, __LINE__);
  }
  if (SchemaNameBufSize > 0) 
  {
    int ix = 0;
    while (ix < SchemaNameBufSize)
    {
      SchemaName[ix] = SchemaNameWyde[ix];
      if (0 == SchemaNameWyde[ix])
      {
        return;
      }
      ++ix;
    }
    m_pSession->ThrowDBError (e_buffer_too_small, "omsGetSchemaName", __MY_FILE__, __LINE__);
  }
}

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

int OmsHandle::omsGetTimeOut() const
{
  return m_pSession->m_timeout;
}

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

OmsCallbackInterface* OmsHandle::omsGetTransactionInterface (const ClassIDRef guid) const
{
  return m_pSession->GetCallbackInterface(guid);
}

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

unsigned long OmsHandle::omsGetVarObjectSize (const OmsVarOid& oid) 
{
  OMS_TRACE (omsTrInterface | omsTrVarObject, m_pSession->m_lcSink, "omsGetVarObjSize : " << oid);
  OMS_CHECK_EXCEPTION(*this);

  return m_pSession->GetVarObjSize(oid);
}

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

void OmsHandle::omsInitSession (IUnknown** s)
{
  m_session = (IliveCacheSink**) s;

  // this will do an attach in simulator, ignored otherwise
  OMS_Globals::KernelInterfaceInstance->SimCtlAttachSink(*this);
}

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

bool OmsHandle::omsIsLocked (const OmsObjectId& oid)
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsIsLocked : " << oid);
  return m_pSession->IsLocked(oid);
}

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

bool OmsHandle::omsIsRegistered(const ClassIDRef guid, OmsSchemaHandle Schema, OmsContainerNo ContainerNo)
{
     OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsIsRegistered : " << guid << "," << Schema << "," << ContainerNo);
     return (NULL != m_pSession->GetClsInfoForReg(guid, Schema, ContainerNo));
}

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

void OmsHandle::omsLoadVarObject (const OmsVarOid& oid, unsigned long size, void* buf)
{
  OMS_TRACE (omsTrInterface | omsTrVarObject, m_pSession->m_lcSink, "omsLoadVarObject : " << oid << ", size " << size);
  OMS_CHECK_EXCEPTION(*this);

  omsIfNilOidThrowError (this, oid, "omsLoadVarObject");
  m_pSession->LoadVarObject(oid, VarObjExclusiveLock, size, buf); 
}

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

void OmsHandle::omsLock( const OmsObjectId&oid )
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsLock : " << oid);
  OMS_CHECK_EXCEPTION(*this);

  m_pSession->CurrentContext()->LockObj(oid);
}

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

void OmsHandle::omsLock( const OmsVarOid& oid)
{ 
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsLock(Var) : " << oid);
  OMS_CHECK_EXCEPTION(*this);

  m_pSession->CurrentContext()->LockObj((OmsObjectId) oid);
}

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

bool OmsHandle::omsTryLock( const OmsObjectId&oid )
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsTryLock : " << oid);
  OMS_CHECK_EXCEPTION(*this);

  return m_pSession->CurrentContext()->TryLockObj(oid);
}

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

bool OmsHandle::omsTryLock( const OmsVarOid& oid)
{ 
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsTryLock(Var) : " << oid);
  OMS_CHECK_EXCEPTION(*this);

  return m_pSession->CurrentContext()->TryLockObj((OmsObjectId) oid);
}

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

void OmsHandle::omsLocks( const OmsObjectId*p, int n )
{ 
  _TRACE_METHOD_ENTRY(this,"omsLocks")
  OMS_CHECK_EXCEPTION(*this);
    
  tsp00_Int4 ix;
  for (ix = 0; ix < n; ++ix) {
    omsLock(*p);
    ++p;
  }
  return;
}

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

void OmsHandle::omsLockMass(OmsIOidReadIterator& oids, short timeout, OmsIOidAppender& errOids)
{
  _TRACE_METHOD_ENTRY(this,"omsLockMass")
  OMS_CHECK_EXCEPTION(*this);

  m_pSession->LockObjMass(oids, timeout, errOids);
}

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

void OmsHandle::omsMarkVersion ( const OmsVersionId& versionId )
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsMarkVersion : " << OMS_CharBuffer(versionId, sizeof(versionId)));
  OMS_CHECK_EXCEPTION(*this);

  OMS_Context*     context;
  { // Begin of exclusive critical section.    // PTS 1124533
    ExclusiveVersionDirRgn rgn(OMS_Globals::m_globalsInstance->m_versionDictionary.GetSingleLockId(versionId),
                               OMS_Globals::m_globalsInstance->m_versionDictionary.UseRWLocks());
    context = OMS_Globals::m_globalsInstance->m_versionDictionary.FindVersion(versionId);
    if (NULL == context) {
      m_pSession->ThrowDBError (e_unknown_version, "omsMarkVersion", versionId, __MY_FILE__, __LINE__);
    }
    context->MarkVersion();
  } // End of exclusive critical section.
}

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

int OmsHandle::omsDerefMass(const OmsIDerefIter &derefIter){
  return m_pSession->MassDeref(*const_cast<OmsIDerefIter*>(&derefIter));
}

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

int OmsHandle::omsDerefMass(const OmsDeref &derefIter){
  return m_pSession->MassDeref(*const_cast<OmsIDerefIter*>(reinterpret_cast<const OmsIDerefIter*>(&derefIter)));
}

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

int OmsHandle::omsDerefMass(const OmsDerefArray &derefIter){
  return m_pSession->MassDeref(*const_cast<OmsIDerefIter*>(reinterpret_cast<const OmsIDerefIter*>(&derefIter)));
}

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

int OmsHandle::omsDerefForUpdMass(const OmsIDerefIterForUpd &derefIter, bool doLock){
  return m_pSession->MassDerefForUpd(*const_cast<OmsIDerefIterForUpd*>(&derefIter), doLock);
}

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

int OmsHandle::omsDerefForUpdMass(const OmsDerefForUpd &derefIter, bool doLock){
  return m_pSession->MassDerefForUpd(*const_cast<OmsIDerefIterForUpd*>(reinterpret_cast<const OmsIDerefIterForUpd*>(&derefIter)),
                                     doLock);
}

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

int OmsHandle::omsDerefForUpdMass(const OmsDerefArrayForUpd &derefIter, bool doLock){
  return m_pSession->MassDerefForUpd(*const_cast<OmsIDerefIterForUpd*>(reinterpret_cast<const OmsIDerefIterForUpd*>(&derefIter)),
                                     doLock);
}

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

int OmsHandle::omsDerefKeyMass(const OmsIDerefKeyIter &derefIter){
  return m_pSession->MassDerefViaKey(*const_cast<OmsIDerefKeyIter*>(&derefIter));
}

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

int OmsHandle::omsDerefKeyMass(const OmsDerefKeyArray &derefIter){
  return m_pSession->MassDerefViaKey(*const_cast<OmsIDerefKeyIter*>(reinterpret_cast<const OmsIDerefKeyIter*>(&derefIter)));
}

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

int OmsHandle::omsDerefKeyMassForUpd(const OmsIDerefKeyIterForUpd &derefIter, bool doLock){
  return m_pSession->MassDerefViaKeyForUpd(*const_cast<OmsIDerefKeyIterForUpd*>(&derefIter), doLock);
}

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

int OmsHandle::omsDerefKeyMassForUpd(const OmsDerefKeyArrayForUpd &derefIter, bool doLock){
  return m_pSession->MassDerefViaKeyForUpd(*const_cast<OmsIDerefKeyIterForUpd*>(reinterpret_cast<const OmsIDerefKeyIterForUpd*>(&derefIter)),
                                           doLock);
}

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

void OmsHandle::omsMethodCallEpilog(void* pSH) {     /* PTS 1120794 */
  OmsCallbackInterface* cbi = m_pSession->GetCallbackInterface();
  if (NULL != cbi) {
    /* PTS 1120794 */
    if (NULL != pSH) {
      cbi->omsMethodCallEpilog(*this,*REINTERPRET_CAST(SqlHandle*,(pSH)));
    }
    else {
      cbi->omsMethodCallEpilog(*this);
    }
  }
}

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

void OmsHandle::omsMonitorLock()
{
  (*m_session)->EnterCriticalSection(RGN_MONITOR);
}

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

void OmsHandle::omsMonitorUnlock()
{
  (*m_session)->LeaveCriticalSection(RGN_MONITOR);
}

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

void OmsHandle::omsNewConsistentView ()
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsNewConsistentView : ");
  if (m_pSession->CurrentContext()->IsVersion()) {
    return;
  }
  OMS_CHECK_EXCEPTION(*this);

  m_pSession->CurrentContext()->LockObjWithBeforeImage();    // PTS 1128108
  m_pSession->CurrentContext()->RemoveUnlockedObjFromCache();
  m_pSession->CurrentContext()->NewConsistentView();
}

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

void OmsHandle::omsNewConsistentView (OmsObjectId* pOids, int cntOids, short timeout)
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsNewConsistentView : " << "cnt " << cntOids << "timeout " << timeout);

  int dummy = 0;
  omsNewConsistentView (pOids, cntOids, timeout, NULL, dummy);
}

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

static bool operator<(const OmsTypeOid &a, OmsTypeOid &b)
{
  if (a.pno == b.pno) {
    return *((&(a.pno)) + 1) < *((&(b.pno)) + 1);
  } else {
    return a.pno < b.pno;
  }
}

void OmsHandle::omsNewConsistentView (OmsObjectId* pOids, int cntOids, short timeout, OmsObjectId* pErrOids, int& cntErrOids)
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsNewConsistentView : " << "cnt " << cntOids << "timeout " << timeout);
  OMS_CHECK_EXCEPTION(*this);

  if (cntOids == 0){
    omsNewConsistentView();
  }
  else {
    gg200QuickSort(reinterpret_cast<OmsTypeOid*>(&pOids[0]), cntOids);

    // PTS 1115027
    OMS_OidArrayReader pOidsIter(pOids, cntOids);
    OMS_OidArrayWriter pErrOidsApp(pErrOids, cntErrOids);

    m_pSession->NewConsistentView(pOidsIter, timeout, pErrOidsApp);
    cntErrOids = pErrOidsApp.omsGetCntr();
  }
}

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

// PTS 1115027

void OmsHandle::omsNewConsistentView (OmsIOidReadIterator& pOids, short timeout, OmsIOidAppender& pErrOids)
{
  OMS_CHECK_EXCEPTION(*this);
  
  m_pSession->NewConsistentView(pOids, timeout, pErrOids);
}

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

OmsAbstractObject* OmsHandle::omsNewKeyedObject(const ClassIDRef	 guid, 
                                                const unsigned char* key,
                                                OmsSchemaHandle      Schema,
                                                OmsContainerNo       ContainerNo )
{
  _TRACE_METHOD_ENTRY(this,"omsNewKeyObject");
  OMS_CHECK_EXCEPTION(*this);

  return m_pSession->NewKeyedObject (guid, key, Schema, ContainerNo);
}

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

OmsAbstractObject* OmsHandle::omsNewObject( const ClassIDRef guid, OmsSchemaHandle Schema, OmsContainerNo ContainerNo )
{
  _TRACE_METHOD_ENTRY(this,"omsNewObject")
  OMS_CHECK_EXCEPTION(*this);

  return m_pSession->NewObject(guid, Schema, ContainerNo);    
}

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

OmsAbstractObject* OmsHandle::omsNewRegistryObject (size_t sz, const ClassIDRef guid)
{
  OmsObjectContainerPtr p;
  sz += OmsObjectContainer::headerSize();
  if (m_pSession->InVersion()) {
    p = (OmsObjectContainerPtr) m_pSession->m_context->allocate(sz); // PTS 1122445
  }
  else {
    p = (OmsObjectContainerPtr) m_pSession->StackHeapMalloc(sz); // PTS 1134841
  }
  if (p) {
    p->InitState(REINTERPRET_CAST(OMS_GuidEntry*, NULL));
    p->UnmarkVerNewObject();
    return &p->m_pobj;
  }
  return NULL;  
}

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

const OmsVarOid& OmsHandle::omsNewVarObject(OmsSchemaHandle Schema, OmsContainerNo ContainerNo)
{
  OMS_TRACE (omsTrInterface | omsTrVarObject, m_pSession->m_lcSink, "omsNewVarObj : " << Schema << ", " << ContainerNo);
  OMS_CHECK_EXCEPTION(*this);

  m_pSession->RegVarObjectContainer (Schema, ContainerNo);
  return m_pSession->NewVarObject(Schema, ContainerNo);
}

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

void  OmsHandle::omsPrintOid (char* buf, size_t bufSize, const OmsObjectId oid)
{
   char auxbuf[256];
   //sprintf ( auxbuf, "OID : %d.%d (vers %d)", oid.getPno(), oid.getPagePos(), oid.getGeneration());                    // PTS 1125307
   sp77sprintf ( auxbuf, sizeof(auxbuf), "OID : %d.%d (vers %d)", oid.getPno(), oid.getPagePos(), oid.getGeneration());  // PTS 1125307
   if (strlen(auxbuf) < bufSize) {
     strcat (buf, auxbuf);
   }
}

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

int OmsHandle::omsOidInfo (const OmsObjectId& oid, 
                           ClassID &Guid, 
                           OmsSchemaHandle& Schema, char* SchemaName, int SchemaNameBufSize,
                           char* ClassName, int ClassNameBufSize, OmsContainerNo& ContainerNo,
                           bool excSafe)
{
  OmsTypeWyde SchemaNameWyde[OMS_MAX_SCHEMA_NAME_LENGTH + 1];

  int rc = omsOidInfo (oid, 
                       Guid, 
                       Schema, SchemaNameWyde, OMS_MAX_SCHEMA_NAME_LENGTH + 1,
                       ClassName, ClassNameBufSize, ContainerNo,
                       excSafe);

  if (SchemaNameBufSize > 0 && SchemaName != NULL){
    WydeToChar(&SchemaNameWyde[0], SchemaName, SchemaNameBufSize, "omsOidInfo");
  }

  return rc;
}

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

int OmsHandle::omsOidInfo (const OmsObjectId& oid, 
                           ClassID &Guid, 
                           OmsSchemaHandle& Schema, OmsTypeWyde* SchemaName, int SchemaNameBufSize,
                           char* ClassName, int ClassNameBufSize, OmsContainerNo& ContainerNo,
                           bool excSafe)
{
  OMS_CHECK_EXCEPTION(*this);
  
  omsIfNilOidThrowError (this, oid, "omsOidInfo");
  OmsObjectContainerPtr pObj = m_pSession->CurrentContext()->GetObj(oid, false);
  if (NULL != pObj) {
    OMS_ClassIdEntry* pContainerInfo = pObj->GetContainerInfo(m_pSession->CurrentContext());
    Guid        = pContainerInfo->GetGuid();
    Schema      = pContainerInfo->GetSchema();
    ContainerNo = pContainerInfo->GetContainerNo();

    if (SchemaNameBufSize > 0 && SchemaName != NULL){
      omsGetSchemaName(Schema, SchemaName, SchemaNameBufSize);
    }

    if (ClassNameBufSize > 0 && ClassName != NULL) {
      int ClassNameLength = (int) strlen(pContainerInfo->GetClassInfoPtr()->GetClassName());
      if (ClassNameLength >= ClassNameBufSize) {
        ClassNameLength = ClassNameBufSize - 1;
      }
      SAPDB_MemCopyNoCheck (ClassName, pContainerInfo->GetClassInfoPtr()->GetClassName(), ClassNameLength); 
      ClassName[ClassNameLength] = 0;
    }

    return 0;
  }
  else {
    if (!excSafe){
      m_pSession->ThrowDBError (e_object_not_found, "omsOidInfo", oid, __MY_FILE__, __LINE__);
    }
    return -1;
  }
}

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

void OmsHandle::omsOpenVersion( const OmsVersionId& versionId )
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsOpenVersion : " << OMS_CharBuffer(versionId, sizeof(versionId)));
  OMS_CHECK_EXCEPTION(*this);

  OMS_Context*        context;
  const char*             msg          = "omsOpenVersion";
  const char*             msgInVersion = "omsOpenVersion, already in version";
 
  if (m_pSession->InVersion()) {
    m_pSession->ThrowDBError (e_already_in_version, msg, m_pSession->CurrentContext()->GetVersionId(), __MY_FILE__, __LINE__); 
  }

  // Check if there are objects which have been changed in the current transaction
  m_pSession->OpenVersionProlog(versionId, false);    // PTS 1129082

  { // Begin of exclusive critical section.    // PTS 1124533
    ExclusiveVersionDirRgn rgn(OMS_Globals::m_globalsInstance->m_versionDictionary.GetSingleLockId(versionId),
                               OMS_Globals::m_globalsInstance->m_versionDictionary.UseRWLocks());
  
    context = OMS_Globals::m_globalsInstance->m_versionDictionary.FindVersion(versionId);
    if (NULL == context) {
      m_pSession->ThrowDBError (e_unknown_version, msg, versionId, __MY_FILE__, __LINE__);
    }
    if (context->IsDropped()) {
      goto Drop;  // The deletion itself is done outside the critical section
    }
    if (m_pSession->IsSubtransOpen()) {
      m_pSession->ThrowDBError (e_too_many_subtrans, "Open Subtrans", versionId, __MY_FILE__, __LINE__); 
    }
    if ((context->IsBoundToTrans()) && (!m_pSession->VersionBoundByMe(context))) 
    {
      tsp00_TaskId tid = context->m_session->GetTaskId();
      char         vId[sizeof(versionId)+1];
      SAPDB_MemCopyNoCheck (&vId[0], &versionId[0], sizeof(versionId));
      vId[sizeof(versionId)] = 0;
      DbpBase b(*m_session);
      if (context->IsVersionOpen())
      {
          b.dbpOpError("%d, %s already opened by T%3d", e_version_already_open, &vId[0], tid);
          m_pSession->ThrowDBError (e_version_already_open, msg, versionId, __MY_FILE__, __LINE__);
      }
      else
      {
          b.dbpOpError("%d, %s bound by T%3d", e_version_bound_by_trans, &vId[0], tid);
          m_pSession->ThrowDBError (e_version_bound_by_trans, msg, versionId, __MY_FILE__, __LINE__);
      }
    }

    m_pSession->OpenVersion(context, false);
    m_pSession->IncOpenVersion();
    OMS_Globals::m_globalsInstance->m_versionDictionary.MarkNotUnloadable(m_pSession->m_lcSink, context);
  } // End of exclusive critical section.

  // Free consistent view of default context
  m_pSession->OpenVersionEpilog();  // PTS 1129082

  return;

Drop:
  {
    try {
      omsForceDropVersion(versionId);
    }
    catch(DbpError&) {
    }
    m_pSession->ThrowDBError (e_unknown_version, msg, versionId, __MY_FILE__, __LINE__);
  }
}

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

void OmsHandle::omsRaiseError (short msgno, const OmsTypeUTF8* errmsg) 
{
  _TRACE_METHOD_ENTRY(this,"omsRaiseError");
  const SAPDB_UTF8* pMsg    = errmsg;
  int               charCnt = 0;
  bool              toUCS2  = false;
  if (OMS_Globals::KernelInterfaceInstance->IsUnicodeInstance())
  {
    while (true)
    {
      if (0 == *pMsg)
      {
        break;
      }
      SAPDB_UInt characterSize = SAPDB_UTF8Basis::CharacterSize(pMsg);
      if (0 == characterSize)
      {
        return;
      }
      if (characterSize > 1)
      {
        toUCS2 = true;
      }
      ++charCnt;
      for (SAPDB_UInt ix = 0; ix < characterSize; ++ix)
      {
        ++pMsg;
      }
    }
  }
  else
  {
    charCnt = (int) strlen((char*) &errmsg[0]); 
  }
  if (toUCS2)
  {
    tsp81_UCS2Char* pUCS2 = REINTERPRET_CAST(tsp81_UCS2Char*, OMS_SharedMemAllocator::allocateImpl((charCnt+1) * 2));  
    SAPDB_UTF8Basis::UTF8ConstPointer srcAt;
    tsp81_UCS2Char*                   destAt;
    SAPDB_UTF8Basis::ConversionResult res = SAPDB_UTF8Basis::KernelConvertToUTF16 (errmsg, pMsg,
      srcAt, pUCS2, pUCS2 + charCnt, destAt, false);
    if (SAPDB_UTF8Basis::Success != res)
    {
      charCnt = 0;
    }
    m_pSession->m_lcSink->SetError (msgno, 2 * charCnt, 
      REINTERPRET_CAST(unsigned char*, pUCS2), csp_unicode);
  }
  else
  {
    m_pSession->m_lcSink->SetError (msgno, charCnt, errmsg, csp_ascii);
  }
};

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

void OmsHandle::omsReadOnly (bool read_only) 
{
  m_pSession->SetReadOnly(read_only);
}

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

bool OmsHandle::omsGetReadOnly()
{
  return m_pSession->GetReadOnly();
}

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

void OmsHandle::omsRegClass (OmsSchemaHandle    Schema,
                             const ClassIDRef   guid,
                             const char*        ClassName, 
                             size_t             PersistentSize,
                             size_t             ObjectSize,
                             const ClassIDPtr   pBaseClass,
                             OmsAbstractObject* Obj, 
                             OmsContainerNo     ContainerNo,
                             size_t             arrayByteSize)
{
  OMS_CHECK_EXCEPTION(*this);

  m_pSession->RegContainer(Schema, guid, ClassName, PersistentSize, ObjectSize, 
    pBaseClass, Obj,  ContainerNo, arrayByteSize);
}

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

void OmsHandle::omsRegClassAndKey (OmsSchemaHandle    Schema, 
                                   const ClassIDRef   guid,
                                   const char*        ClassName,
                                   size_t             PersistentSize, 
                                   size_t             KeySize, 
                                   size_t             ObjectSize, 
                                   OmsAbstractObject* Obj, 
                                   OmsContainerNo     ContainerNo,
                                   bool               partitionedKey /* PTS 1109717 */)
{
  _TRACE_METHOD_ENTRY(this,"OmsHandle::omsRegClassAndKey");
  OMS_CHECK_EXCEPTION(*this);
  
  struct VirtualObject {
    void* vtptr;
  };    
  OMS_ClassIdEntry* pContainerInfo;
  bool              isRegistered = false;
  
  //try {                                    // PTS 1120873
    pContainerInfo = m_pSession->GetClsInfoForReg(guid, Schema, ContainerNo);
    isRegistered = (pContainerInfo != NULL);
  //}                                        // PTS 1120873
  //catch (DbpError& e) {                    // PTS 1120873
  //  if (e_unknown_guid != e.dbpError()) {  // PTS 1120873
  //    throw e;                             // PTS 1120873
  //  }                                      // PTS 1120873
  //}                                        // PTS 1120873
  if (!isRegistered) {
    ObjectSize     += (OmsObjectContainer::headerSize() + KeySize);
    PersistentSize += (KeySize - /* virtual table ptr */ sizeof (void*)); 
    OMS_ContainerInfo* p = OMS_Globals::m_globalsInstance->m_classDictionary.RegisterContainer (*m_session, guid, 
      ClassName, PersistentSize, ObjectSize, NULL, 
      (PersistentSize - KeySize + 1) /*keyPos*/, KeySize, partitionedKey, 
      Schema, ContainerNo, 
      (REINTERPRET_CAST(VirtualObject*, Obj))->vtptr);
    pContainerInfo = omsAddContainerInfo (p);
  }
  /* PTS 1122445, don't chain free object, because we don't know its size any more */
  /* PTS 1139402, free memory only if context is a version, otherwise StackAllocator is used */
  if (m_pSession->InVersion()) 
    m_pSession->m_context->deallocate(OmsObjectContainer::containerPtr(Obj)); 
};

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

void OmsHandle::omsRegMonitor (void* pMon)
{ 
  m_monitor = REINTERPRET_CAST(OMS_COMMonitor*, (pMon)); 
} 

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

void OmsHandle::omsRegTransactionInterface (const ClassIDRef guid, OmsCallbackInterface* pInterface)
{
  m_pSession->RegisterCallbackInterface(guid, pInterface);
}

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

void OmsHandle::omsRelease( const OmsObjectId& oid )
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsRelease : " << oid);
  m_pSession->ReleaseObj(oid);
}

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

void OmsHandle::omsRelease ( const OmsVarOid& oid )
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsRelease : " << oid);
  m_pSession->ReleaseObj ((OmsObjectId) oid); 
};

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

void OmsHandle::omsReleaseAll()
{
  const bool emptyObjCache = true;
  if (!m_pSession->IsSubtransOpen() && !m_pSession->InVersion()) {
    m_pSession->CurrentContext()->FlushObjCache(emptyObjCache);

    // If no subtrans is open, then before images are only generated 
    // if program runs in the simulator. 
    // TODO: Is the following call needed for the simulator??
    //m_pSession->FreeBeforeImages();                                 
  }
  else {
    // Only objects which not have been changed can be released.
    m_pSession->ReleaseAllUnchanged();
  }
}

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

HRESULT OmsHandle::omsReleaseDefaultContext() 
{
  if (NULL != m_monitor) {
    OMS_SessionCriticalSection region(this->m_pSession, RGN_MONITOR);
    region.Enter();
    OMS_Globals::m_globalsInstance->m_monitorDirectory.Insert(m_monitor); /* PTS 1107731 */
    region.Leave();
  }
  
  OMS_TRACE(omsTrSession, (*m_session), " Release Session " << m_pSession << " of Hndl " << this << " RefCnt " << m_pSession->m_refCnt);
  m_pSession->DeleteSession();
  return S_OK;
}

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

void OmsHandle::omsReleaseUnconditional( const OmsObjectId& oid)
{
  m_pSession->ReleaseObjUnconditional (oid); 
}

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

void OmsHandle::omsReleaseVarObject(const OmsVarOid& oid)
{
  OMS_TRACE (omsTrInterface | omsTrVarObject, m_pSession->m_lcSink, "omsReleaseVarObject : " << oid);
  m_pSession->ReleaseVarObject(oid);
}

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

void OmsHandle::omsReleaseConsistentView()
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsReleaseConsistentView");
  tsp00_Int2  DummyError;
  tsp00_Int4  BufLen = 0;
  tsp00_Int4  Buf;
  OMS_HResult hr = (*m_session)->MultiPurpose (m_end, mm_nil, &BufLen, 
    (unsigned char*) &Buf, &DummyError);
}

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

/* PTS 1115134 */
void OmsHandle::omsResetVersion(const OmsVersionId& versionId)
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsResetVersion : " << OMS_CharBuffer(versionId, sizeof(versionId)));
  OMS_CHECK_EXCEPTION(*this);

  const char*  msg  = "omsResetVersion";

  bool isDropped = false;    
  { // Begin of exclusive critical section.    // PTS 1124533
      ExclusiveVersionDirRgn rgn(OMS_Globals::m_globalsInstance->m_versionDictionary.GetSingleLockId(versionId),
                                 OMS_Globals::m_globalsInstance->m_versionDictionary.UseRWLocks());

    OMS_Context* context = OMS_Globals::m_globalsInstance->m_versionDictionary.FindVersion(versionId);
    if (NULL == context) {
      m_pSession->ThrowDBError (e_unknown_version, msg, versionId, __MY_FILE__, __LINE__);
    }
    if (context->IsDropped()) {
      isDropped = true;
    }
    if (m_pSession->IsSubtransOpen()) {
      m_pSession->ThrowDBError (e_too_many_subtrans, msg, versionId, __MY_FILE__, __LINE__); 
    }
    if (context->IsBoundToTrans()) 
    {
        m_pSession->ThrowDBError (e_version_already_open, msg, versionId, __MY_FILE__, __LINE__);
    }
    context->ResetVersion(*m_pSession);
  } // End of exclusive critical section. 

  if (isDropped){
    try {
      omsForceDropVersion(versionId);
    }
    catch(DbpError&) {
    }
    m_pSession->ThrowDBError (e_unknown_version, msg, versionId, __MY_FILE__, __LINE__);
  }
}

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

void OmsHandle::omsRollback (bool doRelease, bool ignoreErrors)
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsRollback");
  int phase = 1;
  try
  {
    // no application wanted exceptions in the course of transaction end
    this->omsControlCancelFlag(-1);
    this->omsControlDbpException(-1);
    if (!ignoreErrors)
    {
      m_pSession->RollbackSubtrans(1, true);
    }
    phase = 2;
    m_pSession->FreeBeforeImages();
    phase = 3;
    m_pSession->ClearDefaultContext();
    phase = 4;
    OmsCallbackInterface* callbackInterface = m_pSession->GetCallbackInterface();
    phase = 5;
    if (NULL != callbackInterface) {
      bool read_only = m_pSession->ForceReadOnly();
      try {
        callbackInterface->omsInvalidate (*this, OmsCallbackInterface::AfterRollback,
          m_pSession->InVersion());
        m_pSession->m_lcSink->UserAllocatorCtl(OmsCallbackInterface::BlockTransaction, NULL);  // check TX allocator empty
      }
      catch (DbpError &e) {
        dbpOpError("omsInvalidate failed with DbpError %d (%s)", e.dbpError(), e.m_errorText);
        m_pSession->m_currVarObjChunk.m_oid.setNil();
        m_pSession->ResetSubtransLevel();
        m_pSession->UnforceReadOnly(read_only);
        m_pSession->ClearDefaultContext();
        throw e;
      }
      catch (BAD_ALLOC_GEO573 &e) {
        dbpOpError("omsInvalidate failed with BAD_ALLOC");
        m_pSession->m_currVarObjChunk.m_oid.setNil();
        m_pSession->ResetSubtransLevel();
        m_pSession->UnforceReadOnly(read_only);
        m_pSession->ClearDefaultContext();
        throw e;
      }
      catch (...) {
        dbpOpError("omsInvalidate failed with unknown exception");
        m_pSession->m_currVarObjChunk.m_oid.setNil();
        m_pSession->ResetSubtransLevel();
        m_pSession->UnforceReadOnly(read_only);
        m_pSession->ClearDefaultContext();
        throw;
      }
      m_pSession->m_currVarObjChunk.m_oid.setNil();
      m_pSession->UnforceReadOnly(read_only);
      if (!m_pSession->InVersion()) {
        m_pSession->ResetSubtransLevel();
        m_pSession->ClearDefaultContext();
      }
    }
    phase = 6;
	m_pSession->TransEnd();
	phase = 7;
    if (doRelease) 
	{
      this->SessionEnd();  /* PTS 1107209 */
    }
  }
  catch (DbpError& e)
  {
    if (!ignoreErrors)
    { 
      dbpOpError("omsRollback failed with error %d in phase %d (%s)", e.dbpError(), phase, e.m_errorText);
      omsTerminate();
    }
    else {
      DbpErrorCallbackInterface *pCBInterface = DbpError::dbpGetCallback();  // PTS 1127871
      if (pCBInterface){
        pCBInterface->dbpCaughtError(e);
      }
    }
  }
  catch (BAD_ALLOC_GEO573&)
  {
    if (!ignoreErrors)
    { 
      dbpOpError("omsRollback failed with BAD_ALLOC in phase %d", phase);
      omsTerminate();
    }
    else {
      DbpErrorCallbackInterface *pCBInterface = DbpError::dbpGetCallback();  // PTS 1127871
      if (pCBInterface){
        pCBInterface->dbpCaughtBadAlloc();
      }
    }
  }
  catch (...)
  {
    if (!ignoreErrors)
    { 
      dbpOpError("omsRollback failed with unknown exception in phase %d", phase);
      omsTerminate();
     }
  }
}

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

void OmsHandle::omsRollbackSubtrans( int required_lvl )
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsRollbackSubtrans : " << required_lvl);
  if (!m_pSession->IsSubtransOpen()) {
    return;
  }
  OMS_CHECK_EXCEPTION(*this);
  m_pSession->IncSubtransRollback();
  m_pSession->RollbackSubtrans(required_lvl, false);
}

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

void OmsHandle::omsRenameVersion ( const OmsVersionId& oldId, const OmsVersionId& newId)
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsRenameVersion : " << OMS_CharBuffer(oldId, sizeof(oldId)) 
    << " to " << OMS_CharBuffer(newId, sizeof(newId)));
  OMS_CHECK_EXCEPTION(*this);

  const char* msg = "omsRenameVersion";

  { // Begin of exclusive critical section.    // PTS 1124533
    int   pLock[2];
    const OmsVersionId *pVersionId[2];
    pVersionId[0] = &newId;
    pVersionId[1] = &oldId;
    int size = 2;
    OMS_Globals::m_globalsInstance->m_versionDictionary.GetMultiLockIds(pVersionId, size, &pLock[0]);
    ExclusiveVersionDirRgn rgn(pLock, size,
                               OMS_Globals::m_globalsInstance->m_versionDictionary.UseRWLocks());

    OMS_Context* context = OMS_Globals::m_globalsInstance->m_versionDictionary.FindVersion(oldId);
    if (NULL == context) {
      m_pSession->ThrowDBError(e_unknown_version, msg, oldId, __MY_FILE__, __LINE__);
    }

    // PTS 1125433 Check that version is not bound by another session
    if ((context->IsBoundToTrans()) && (!m_pSession->VersionBoundByMe(context))){
      m_pSession->ThrowDBError (e_version_bound_by_trans, msg, oldId, __MY_FILE__, __LINE__);
    }

    // PTS 1125433 Changed calling sequence of drop and insert
    OMS_Globals::m_globalsInstance->m_versionDictionary.DropVersion(oldId); 
    context->RenameVersion (oldId, newId);

    tgg00_BasisError e = OMS_Globals::m_globalsInstance->m_versionDictionary.InsertVersion(newId, context);
    if (e_ok != e) {
      if (e_duplicate_key == e) {
        e = e_duplicate_name;
      }
      // PTS 1125433 Re-Insert version after error occurred
      context->RenameVersion (newId, oldId);
      OMS_Globals::m_globalsInstance->m_versionDictionary.InsertVersion(oldId, context);

      m_pSession->ThrowDBError (e_duplicate_name, msg, newId, __MY_FILE__, __LINE__);
    }
    //OMS_Globals::m_globalsInstance->m_versionDictionary.DropVersion(oldId); 
    //context->RenameVersion (oldId, newId);
  } // End of exclusive critical section.
}

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

void OmsHandle::omsSetTimeOut( short timeout )
{
  tsp00_Int2  DummyError;
  tsp00_Int4  BufLen = sizeof(timeout);
  m_pSession->m_timeout = timeout;
  OMS_HResult hr = (*m_session)->MultiPurpose (m_set, mm_lock_timeout, &BufLen, 
    (unsigned char*) &timeout, &DummyError);
}

// PTS 1117571
/*----------------------------------------------------------------------*/
// Switch ON or OFF the feature of CACHED KEYS. 
bool OmsHandle::omsSetCachedKeys(bool on, 
                                 const ClassIDRef guid, 
                                 OmsSchemaHandle schema, 
                                 OmsContainerNo containerNo)
{
  OMS_TRACE (omsTrInterface | omsTrContainerDir, m_pSession->m_lcSink, "omsSetCachedKeys: " << (on?"ON":"OFF"));
  OMS_CHECK_EXCEPTION(*this);

  OMS_ClassIdEntry* pClsInfo = m_pSession->GetClsInfo (guid, schema, containerNo);
  return pClsInfo->SetCachedKeys(on, m_pSession->CurrentContext());
}

/*----------------------------------------------------------------------*/
// PTS 1117690
void OmsHandle::omsSetCurrVersionDesc (const char* desc)
{ 
  if (desc == NULL){
    omsSetCurrVersionDesc(reinterpret_cast<OmsTypeWyde*>(NULL));
  }
  else{
    OmsTypeWyde descBuf_wyde[OMS_MAX_VERSION_DESC_LENGTH + 1];
    int len = strlen(desc);
    int len_byte = (OMS_MAX_VERSION_DESC_LENGTH + 1) * sizeof(OmsTypeWyde);

    tsp00_Uint4 destBytesWritten;
    tsp00_Uint4 srcBytesParsed;
    tsp78ConversionResult error;

    // Convertion from ASCII to UCS2  
    error = sp78convertString(sp77encodingUCS2Native,  // destEndcoding
                              descBuf_wyde,            // destBuffer
                              len_byte,                // destBufferLengthInBytes
                              &destBytesWritten,       // destBytesWritten
                              true,                    // addZeroTerminator
                              sp77encodingAscii,       // srcEncoding
                              desc,                    // srcBuffer
                              len,                     // srcBufferLengthInBytes
                              &srcBytesParsed);        // srcBytesParsed
        
    if (error == sp78_Ok){
      // Description is only set if there are no errors in convertion
      omsSetCurrVersionDesc(descBuf_wyde);
    }
  }
}

/*----------------------------------------------------------------------*/
// PTS 1117690
void OmsHandle::omsSetCurrVersionDesc (const OmsTypeWyde* desc)
{ 
  m_pSession->CurrentContext()->SetVersionDesc(desc);
}

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


int OmsHandle::omsStartSubtrans()
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsStartSubtrans");
  OMS_CHECK_EXCEPTION(*this);

  return m_pSession->StartSubtrans();
}

/*----------------------------------------------------------------------*/
// PTS 1122839
void OmsHandle::omsStoreErrorCode(long errorCode) 
{
  m_pSession->StoreErrorCode(errorCode);
}

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

void OmsHandle::omsStoreVarObject ( const OmsVarOid& oid, const void* pVarObj, unsigned long objLength)
{
  OMS_TRACE (omsTrInterface | omsTrVarObject, m_pSession->m_lcSink, "omsStoreVarObject : " << oid << ", length is " << objLength);
  OMS_CHECK_EXCEPTION(*this);

  if (!m_pSession->IsLocked(oid))
  {
    m_pSession->ThrowDBError (e_object_not_locked, "omsStoreVarObject", oid, __MY_FILE__, __LINE__);
  }
  m_pSession->StoreVarObject(oid, pVarObj, objLength);
}

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

void OmsHandle::omsTerminate()
{
  omsTerminate((OmsTypeUTF8*) "");
}

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

void OmsHandle::omsTerminate(const char* msg)
{
  omsTerminate((OmsTypeUTF8*) msg);
}

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

void OmsHandle::omsTerminate(const OmsTypeUTF8* msg) /* PTS 1109963 */
{
  dbpOpMsg("omsTerminate called %s", msg);
  tgg00_BasisError e = e_terminate; /* PTS 1107666 */
  tsp00_Int4  BufLen = sizeof(e);
  tsp00_Int2  SqlError;
  m_pSession->IncOmsTerminate();

#if defined(OMSTST)
  // As variable is reset in CurrentMethodCallEpilog, remember current value.
  // PTS 1127978
  bool requiredExceptionThrown = m_pSession->RequiredExceptionThrown();
#endif

  m_pSession->CurrentMethodCallEpilog(-1); // PTS 1126796
  // transform basis error into sql return code
  m_pSession->m_lcSink->MultiPurpose (m_change, mm_nil, &BufLen, 
    (unsigned char*) &e, &SqlError);

#if defined(OMSTST)
  if (requiredExceptionThrown)
  {
    char* errMsg = "-28999";
    //omsRaiseError (SqlError, (OmsTypeUTF8*) errMsg);
    m_pSession->m_lcSink->SetError (SqlError, 7, (OmsTypeUTF8*)errMsg, csp_ascii);
  }
#endif

/*  omsRaiseError (SqlError, msg); PTS 1123201, PG
    OMS_Globals::KernelInterfaceInstance->IsUnicodeInstance() ist TRUE iff parameter _UNICODE == YES.
    omsIsUnicodeInstance() is TRUE iff 1. parameter _UNICODE == YES and
                                       2. either USERS.DEFAULTCODE == UNICODE for the standard LC user
                                          or     USERS.DEFAULTCODE == DEFAULT for the standard LC user
                                                 and parameter DEFAULT_CODE == UNICODE.

    Standard LC user is the user under which the Dbsl connects to the LC.
    Newer versions of the 6.20 Dbsl and higher allow only connections 
      - from an Ascii SAP system to an Ascii LC and
      - from an Unicode SAP system to an Unicode LC.
    Where   Ascii LC means omsIsUnicodeInstance() == FALSE
      and Unicode LC means omsIsUnicodeInstance() == TRUE.
    So, in case OMS_Globals::KernelInterfaceInstance->IsUnicodeInstance() && !omsIsUnicodeInstance()
    the error text needs to be adjusted. Otherwise question marks occur in ABAP short dumps. */

  if ( OMS_Globals::KernelInterfaceInstance->IsUnicodeInstance()
       && !omsIsUnicodeInstance() ) {

    tsp00_Uint4           destBytesWritten;
    tsp00_Uint4           srcBytesParsed;
    tsp78ConversionResult error;
    tsp00_Int4            srcLenByte = (int)strlen((char*)&msg[0]);
    int                   charCnt = 2 * srcLenByte;
    tsp00_Int4            destLenByte = charCnt + 2;

    OmsTypeUTF8 * pDest = (OmsTypeUTF8 *)m_pSession->m_context->allocate(destLenByte);
    error = sp78convertString( sp77encodingUCS2,      // destEndcoding
                               pDest,                 // destBuffer
                               destLenByte,           // destBufferLengthInBytes
                               &destBytesWritten,     // destBytesWritten
                               true,                  // addZeroTerminator
                               sp77encodingUTF8,      // srcEncoding
                               msg,                   // srcBuffer
                               srcLenByte,            // srcBufferLengthInBytes
                               &srcBytesParsed );     // srcBytesParsed

    if (sp78_Ok == error) {
      m_pSession->m_lcSink->SetError( SqlError, charCnt, pDest, csp_ascii );
    }
    else { /* If the conversion fails, call omsRaiseError as before. */
      omsRaiseError( SqlError, msg );
    }

  }

  else {
    omsRaiseError( SqlError, msg );
  }

}

/*----------------------------------------------------------------------*/
// PTS 1110812
void OmsHandle::omsThrowCancelledError() const
{
  *m_pCancelFlag = false;
  OMS_Globals::Throw(DbpError (DbpError::DB_ERROR, -102, "cancelled", __MY_FILE__, __LINE__));
}

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

void OmsHandle::omsTrace (const char* tracemsg, int TraceMsgLen) {
  if (NULL != *m_session)
    (*m_session)->Vtrace (TraceMsgLen, (unsigned char*) tracemsg);
}

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

void OmsHandle::omsTracef( const char*fmt, ... )
{
#if defined(WIN32)
  char buffer[256];
#else
  char buffer[1024];
#endif

  va_list args;
  va_start (args, fmt);
#if defined(WIN32)
  _vsnprintf ( buffer, sizeof(buffer), fmt, args );
#else
  vsprintf ( buffer, fmt, args );
  buffer[256] = '\0';
#endif
  omsTrace (buffer, (tsp00_Int4) strlen(buffer));
  va_end (args);
}

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

void OmsHandle::omsTraceOid (const OmsObjectId& oid)
{
  omsTracef ("OID : %d.%d (vers %d)", oid.getPno(), oid.getPagePos(), oid.getGeneration());
}

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

void OmsHandle::omsUnlock (const OmsObjectId& oid)
{
  OMS_TRACE (omsTrInterface, m_pSession->m_lcSink, "omsUnlock : " << oid);
  m_pSession->UnlockObj(oid);
}

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

void OmsHandle::omsTransEndEpilog() // PTS 1110287
{
  m_pSession->TransEndEpilog();
}

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

void OmsHandle::omsValidate()
{
}

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

/*!
 * Global allocator is used to allocate memory globally. Applications
 * should use the global allocator only exceptionally, to allocate
 * objects that live longer than a session.
 *
 * \return reference to the global allocator.
 *
 * \see \ref omsuserallocator
 */
OmsAllocatorInterface &OmsHandle::omsGetGlobalAllocator()
{
  OmsAllocatorInterface *alloc;
  m_pSession->m_lcSink->GetGlobalUserAllocator(alloc, NULL);
  return *alloc;
}

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

/*!
 * Global allocator is used to allocate memory globally. Applications
 * should use the global allocator only exceptionally, to allocate
 * objects that live longer than a session.
 *
 * \param name allocator name.
 *
 * \return reference to the specified named global allocator.
 *
 * \see \ref omsuserallocator
 */
OmsAllocatorInterface &OmsHandle::omsGetGlobalAllocator(const char *name)
{
  OmsAllocatorInterface *alloc;
  m_pSession->m_lcSink->GetGlobalUserAllocator(alloc, name);
  return *alloc;
}

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

/*!
 * Session allocator should be used to allocate objects that live until
 * the end of the session. Session allocator will be checked for leftovers
 * on session end. If there was a callback registered, then it will be
 * called for each left-over block.
 *
 * The allocators are actually instantiated at session start time, so this
 * method is exception safe.
 *
 * \return reference to the session-specific allocator.
 *
 * \see \ref omsuserallocator
 */
OmsAllocatorInterface &OmsHandle::omsGetSessionAllocator()
{
  OmsAllocatorInterface *alloc;
  m_pSession->m_lcSink->GetSessionUserAllocator(alloc);
  return *alloc;
}

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

/*!
 * Transaction allocator should be used to allocate objects that live until
 * the end of the transaction. Transaction allocator will be checked for leftovers
 * on commit or rollback. If there was a callback registered, then it will be
 * called for each left-over block.
 *
 * The allocators are actually instantiated at session start time, so this
 * method is exception safe.
 *
 * \return reference to the transaction-specific allocator.
 *
 * \see \ref omsuserallocator
 */
OmsAllocatorInterface &OmsHandle::omsGetTransactionAllocator()
{
  OmsAllocatorInterface *alloc;
  m_pSession->m_lcSink->GetTransactionUserAllocator(alloc);
  return *alloc;
}

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

/*!
 * COM-routine allocator should be used to allocate objects that live only
 * in one COM-routine. COM-routine allocator will be checked for leftovers
 * after each COM-routine. If there was a callback registered, then it will
 * be called for each left-over block.
 *
 * The allocators are actually instantiated at session start time, so this
 * method is exception safe.
 *
 * \return reference to the COM routine-specific allocator.
 *
 * \see \ref omsuserallocator
 */
OmsAllocatorInterface &OmsHandle::omsGetCOMRoutineAllocator()
{
  OmsAllocatorInterface *alloc;
  m_pSession->m_lcSink->GetCOMRoutineUserAllocator(alloc);
  return *alloc;
}

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

OmsHandle::~OmsHandle ()
{
    _TRACE_METHOD_ENTRY(this,"~OmsHandle");
    // Remove Handle from HandleList         // PTS 1116693
  	if (m_pSession) {
  		for (cgg251dclIterator<OmsHandle*,OMS_Session> iter 
  		    = m_pSession->m_handleList.begin(); iter; ++iter) {
            if (this == *iter()) {
                m_pSession->m_handleList.remove(iter);
                break;
            }
        }
    }

    if (OMS_Globals::m_globalsInstance->InSimulator() && m_pSession && m_pSession->m_lcSink) {
        m_pSession->m_lcSink->SimCtlDestroyHandleCB(*this, &(m_pSession->m_lcSink));
    }
}

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

// Class is only needed because the ADT OMS_DynamicStack uses the assignment
// operator to copy the data into the stack. As OmsVersionId is only a struct
// a new class with assignment operator is needed.
class OMS_VersionId 
{
private:
  OmsVersionId vId;

public:
  OMS_VersionId(const OmsVersionId &id)    { memcpy(&vId[0], &id[0], sizeof(OmsVersionId)); }
  void operator= (const OmsVersionId &id)  { memcpy(&vId[0], &id[0], sizeof(OmsVersionId)); } 
  const OmsVersionId& GetId() const        { return vId; }
};

void OmsHandle::omsCleanUpAfterInitialization()
{
  ///////////////////////////////////////////////////////////////////////
  // Cleanup global version directory
 
  OMS_DynamicStack<OMS_VersionId,OMS_Session> stack;
  stack.Advise(m_pSession, 100);

  if (m_pSession->InVersion()){
    omsCloseVersion(*omsCurrentVersionId());
  }

  // Critical section is used to synchronize the access to the global iterator
  // structure. It is NOT used to synchronize access to the version dictionary.
  OMS_SinkCriticalSection cs(m_pSession->m_lcSink, RGN_VERSION_DIR);
  cs.Enter();

  // Reset the global iterator
  OMS_Globals::m_globalsInstance->m_versionIter.Reset(OMS_LOCK_EXCLUSIVE);

  while (true){
    // Position the iterator on the next slot in the hash of the version directory.
    OMS_Context *pContext = OMS_Globals::m_globalsInstance->m_versionIter.GetFirstInSlot();

    if (!pContext)
      break;

    while (pContext){
      OMS_Context *pNext = OMS_Globals::m_globalsInstance->m_versionIter.GetNextInSlot();
      OMS_VersionId vId(pContext->GetVersionId());
      stack.Push(vId);
      pContext = pNext;
    }
    OMS_Globals::m_globalsInstance->m_versionIter.ReleaseSlot();

    // Deletion is done is a separate loop, as during the iteration a lock on the hash chain
    // is hold which would collide with the lock which is acquired in omsForceDropVersion
    while (!stack.IsEmpty()){
      omsDropVersion(stack.Pop()->GetId());
    }
  }

  ///////////////////////////////////////////////////////////////////////
  // Reset statistics
  m_pSession->m_lcSink->ResetMonitor();
}


