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

  module      : vbd93.cpp

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

  responsible : FerdiF

  special area: continuation files for handling objects of variable length
  description : description ...


  version     : 7.4.4.1
  last changed: 2003-09-08  11:49
  see also    : example.html ...

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

  copyright:    (c) 1998-2004 SAP AG



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

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

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

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


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



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

#include "hbd93.h"

#include "gsp03.h"
#include "gsp03_3.h"
#include "gbd05.h"
#include "hbd06.h"      /* PTS 1127804 FF 2004-FEB-17 */
#include "gbd900.h"
#include "gbd910.h"
#include "gbd930.h"

#include "hbd90.h"
#include "hbd91.h"
#include "heo66.h"
#include "hgg01_1.h"
#include "hgg01_3.h"
#include "SAPDB/SAPDBCommon/SAPDB_RangeCode.hpp" // Kernel_move_and_fill
#include "hgg10.h"
#include "hkb67.h" 

#include "liveCache/LVC_Types.hpp"
#include "Converter/Converter_IPageNoManager.hpp"
#include "KernelCommon/Kernel_OpMsg.hpp"            /* PTS 1114891 FF 2002-03-14 */

#if COMPILEMODE_MEO00 >= SLOW_MEO00 
#include "hta99.h"
#endif

/*===========================================================================*
 *  DEFINES                                                                  *
 *===========================================================================*/

#ifdef NO_INLINES
# define _INLINE
#else
# define _INLINE    inline
#endif

#define NO_ALIGNMENT 1

#if defined (BIT64)
# define  ALIGNMENT 8
#else
# define  ALIGNMENT 4
#endif

/*===========================================================================*
 *  MACROS                                                                   *
 *===========================================================================*/

/*===========================================================================*
 *  EXTERNAL VARIABLES                                                       *
 *===========================================================================*/

extern cbd900_ObjFileDir          bd90ObjFileDir;
extern cbd930_GarbCollController  bd91GarbCollController;

/*===========================================================================*
 *  LOCAL VARIABLES                                                          *
 *===========================================================================*/
 
cbd900_ContObjFileDir bd93ContObjFileDir;

/*===========================================================================*
 *  LOCAL FUNCTIONS (PROTOTYPES)                                             *
 *===========================================================================*/

static _INLINE void
bd93_CheckContObjRoot (const tgg92_KernelOid      &RootOId,         //[inp] 
					   const tbd900_ContObjHeader &ContObjHeader    //[inp]
					   );

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

_INLINE static void
bd93_FindFileNoForThisObjBodySize (
								   const tsp00_Uint4      NewObjBodySize, //[inp]  
								   const tgg00_ObjFileNo  ObjFileNo,      //[inp] 
								   tsp00_Int4            &ContFileNo,     //[out]
								   tgg00_BasisError      &TrError);       //[out]

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

_INLINE static void
bd93_GetContObjBodyPointer (tbd_current_tree       &Current,         //[inp/out]
						    const tsp00_Int4        ContObjFileNo,   //[inp]     
						    const tsp00_PageNo      ContObjPno,      //[inp] 
						    const tgg00_ObjPagePos  ContObjPos ,     //[inp]
						    const tgg92_KernelOid  &OId,             //[inp] 
						    tgg00_MessType_Enum     MessType,        //[inp]
						    cbd05_Current          &ContCurrent,     //[out]
						    cbd910_ContObjDataNode &NptrsBody,       //[out]
							tsp00_MoveObjPtr       &pObjBody);       //[out]

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

static void 
bd93_NewContObj (tbd_current_tree        &Current,                 // [inp]
				 tsp00_Int4               ContFileNo,              // [inp]
				 const tgg92_KernelOid   &RootOId,                 // [inp] 
				 cbd900_ContObjFileInfo  &ContObjFileInfo,         // [inp]
				 cbd05_Current           &ContCurrent,             // [out]
				 cbd910_ContObjDataNode  &NptrsBody,               // [out]
				 tgg00_ObjPagePos        &ContObjPos,              // [out]
				 bool                    &bNewContFileWasCreated); // [out]

/*---------------------------------------------------------------------------*/
			
_INLINE static void 
bd93_NewContObjFromThisPage (tbd_current_tree        &Current,                  // [inp]
							 cbd910_ContObjDataNode  &NptrsBody,                // [inp]
							 const tgg92_KernelOid   &RootOId,                  // [inp]
							 tgg00_ObjPagePos        &ContObjPos);              // [out]

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

_INLINE static double
bd93_OccupancyRate (int ObjBodyLen,
					int Alignment);

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

_INLINE static void
bd93_ReleaseContObjFrame (tbd_current_tree       &Current,
						  const tgg92_KernelOid  &OId,            
						  cbd910_ContObjDataNode &NptrsPage,
						  const tgg00_ObjPagePos  ContObjPos);
	
/*===========================================================================*
 *  GLOBAL FUNCTIONS (CODE)                                                  *
 *===========================================================================*/

externCpp void
bd93GetContObjFileStatistics (tbd_current_tree  &Current,
							  tsp00_Int4        &NumAllContPages,
							  tsp00_Int4        &NumFreeContPages,
							  tsp00_Int4        &NumEmptyContPages)
{
    ROUTINE_DBG_MSP00 ("bd93GetContObjFileStatistics");
	
	/* the number of pages in all continuation files is calculated */
	
	tgg00_BasisError       &TrError         = Current.curr_trans->trError_gg00;
	tsp00_PageNo            SubRoot;
	const tgg00_ObjFileNo   ObjFileNo       = Current.curr_tree_id.fileObjFileNo_gg00();  //PTS 1111901 AK 24/09/2001
	cbd900_ContObjFileInfo &ContObjFileInfo = bd93ContObjFileDir[ObjFileNo];

	NumAllContPages   = 0;
	NumFreeContPages  = 0;
	NumEmptyContPages = 0;
	
	/* go trough all continuation files */
	for (int iContFileNo=1;
     	(iContFileNo <= ContObjFileInfo.cfiNumContFiles_bd900) && (TrError == e_ok);
	     ++iContFileNo)
	{
		/* construct Current */
        cbd05_Current ContCurrent (*Current.curr_trans, m_select);	
		ContObjFileInfo.bd900BuildFileId(ObjFileNo, iContFileNo, ContCurrent.curr_tree_id);
				 
		/* go trough all subroots of the file and sum the page counters */      
		const int & MaxNumChains = ContObjFileInfo[iContFileNo].GetChainCount();
			 
		for (int iChain=0; iChain<MaxNumChains; ++iChain)
		{
			SubRoot = ContObjFileInfo[iContFileNo][iChain].ociSubRoot_bd900;       
			cbd910_SubRootNode  NptrsSubRoot (ContCurrent, SubRoot, nr_for_read);			
			if (TrError != e_ok) return;
			
			cbd900_SubRootPageInfo SubRootPageInfo (NptrsSubRoot);
			
			NumAllContPages     += SubRootPageInfo.bd900AllPageCnt();
			NumFreeContPages    += SubRootPageInfo.bd900FreePageCnt();
		}
	}
}

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

externCpp void
bd93GetVarObjBody (tbd_current_tree      &Current,            //[inp\out] 
				   const tgg92_KernelOid &OId,                //[inp] 
				   tsp00_Int4             ExtObjBodySize,     //[inp]
				   void                  *pExtObjBody,        //[inp]
				   tbd900_ObjFrame       *pObjFrame)          //[inp]
{
	
  ROUTINE_DBG_MSP00 ("bd93GetVarObjBody");
	
	/* this function copies the object body identified by       */ 
	/* the OId at the position given by the pointer pExtObjBody */
	
  tgg00_BasisError      &TrError    = Current.curr_trans->trError_gg00;
	
  if (pObjFrame->objHeader_bd900.ohdState_gg92 != obsOccupied_egg00)
  {
    SAPDB_RangeFill (__FILE__, 1, 
            ExtObjBodySize, pExtObjBody, 1, 
            ExtObjBodySize, NIL_OBJ_FILLCHAR_BD900, 
            TrError);
  }
	else
  {
		/*  move object body into output array assigned by pExtObjBody */

		/*  get pointer to the object body*/
		tsp00_MoveObj          *pObjBody;
		cbd05_Current           ContObjCurrent;	
		cbd910_ContObjDataNode  NptrsBody (ContObjCurrent, nr_for_read);
		tbd900_VarObjBody      &VarObjBody    = *((tbd900_VarObjBody*) (pObjFrame->objBody_bd900));
		const tsp00_Int4       &ObjBodySize   = VarObjBody.vbdHeader_bd900.vhdObjSize_bd900;
		const tsp00_Int4       &ContObjFileNo = VarObjBody.vbdHeader_bd900.vhdContObjFileNo_bd900;
		      tsp00_Int4        MaxObjBodySize;
   	const tgg00_ObjFileNo   ObjFileNo     = Current.curr_tree_id.fileObjFileNo_gg00(); //PTS 1111901 AK 24/09/2001
		const tsp00_Bool       &ObjectIsSplit = VarObjBody.vbdHeader_bd900.vhdObjectIsSplit_bd900; // PTS 1121823

		/* check if the given memory is large enough to accomodate the object */
    if (ExtObjBodySize < ObjBodySize)
    {
        Kernel_OpWarning  opErrMsg( csp3_bd_msg, csp3_n_obj );
        opErrMsg << "bd90_GetObjBody:ExtObjBodySize:" << ExtObjBodySize 
            << " ObjBodySize:" << ObjBodySize
            << " ObjFileNo:" << ObjFileNo
            << " ContObjFileNo:" << ContObjFileNo
            << " OID=" << OId.gg92GetPno() << "." << OId.gg92GetPos() << " (vers " << OId.gg92GetFrameVers() << ")";
        TrError = e_wrong_object_version; //e_buffer_limit PTS 1114891 FF 2002-03-15 ;
        return;
	}

    /*  get pointer to the var object body */
		if (0==ContObjFileNo)
		{
      // Object is completely stored in the primary container
      pObjBody       = (tsp00_MoveObj*) VarObjBody.vbdBody_bd900;
      MaxObjBodySize = bd90ObjFileDir[ObjFileNo].GetObjBodySize();

      SAPDB_RangeMove( __FILE__, 21, 
            MaxObjBodySize, ExtObjBodySize,
            pObjBody,    1,
            pExtObjBody, 1,
            ObjBodySize, 
            TrError);
		}
		else if (!ObjectIsSplit)
		{
      // Object is completely stored in the continuation container. This case should only occur
      // for objects which have been stored before the modification of PTS 1121823
			const tsp00_PageNo     &ContObjPno    = VarObjBody.vbdHeader_bd900.vhdContObjPno_bd900;
			const tgg00_ObjPagePos &ContObjPos    = VarObjBody.vbdHeader_bd900.vhdContObjPos_bd900;
      MaxObjBodySize = bd93ContObjFileDir[ObjFileNo][ContObjFileNo].GetObjBodySize();
			
      bd93_GetContObjBodyPointer (Current, ContObjFileNo, ContObjPno, ContObjPos, OId,
				m_select, ContObjCurrent, NptrsBody, pObjBody);
			if (TrError != e_ok) return;

      SAPDB_RangeMove( __FILE__, 22, 
            MaxObjBodySize, ExtObjBodySize,
            pObjBody,    1,
            pExtObjBody, 1,
            ObjBodySize, 
            TrError);
		}
    else 
    {
      // Object is split across the primary and the continuation container
      tsp00_Int4  PrimBodySize = bd90ObjFileDir[ObjFileNo].GetObjBodySize();

      // First read the portion stored in the primary container...
      pObjBody       = (tsp00_MoveObj*) VarObjBody.vbdBody_bd900;
      MaxObjBodySize = bd90ObjFileDir[ObjFileNo].GetObjBodySize();

      SAPDB_RangeMove( __FILE__, 23, 
            MaxObjBodySize, ExtObjBodySize,
            pObjBody,    1,
            pExtObjBody, 1,
            PrimBodySize, 
            TrError);
   
      // ... then read portion stored in the continuation container and copy it
      // beyond the data of the primary container
			const tsp00_PageNo     &ContObjPno    = VarObjBody.vbdHeader_bd900.vhdContObjPno_bd900;
			const tgg00_ObjPagePos &ContObjPos    = VarObjBody.vbdHeader_bd900.vhdContObjPos_bd900;
      MaxObjBodySize = bd93ContObjFileDir[ObjFileNo][ContObjFileNo].GetObjBodySize();
			
      bd93_GetContObjBodyPointer (Current, ContObjFileNo, ContObjPno, ContObjPos, OId,
				m_select, ContObjCurrent, NptrsBody, pObjBody);
			if (TrError != e_ok) return;

      SAPDB_RangeMove( __FILE__, 24, 
            MaxObjBodySize, ExtObjBodySize,
            pObjBody,    1,
            pExtObjBody, 1 + PrimBodySize,
            ObjBodySize-PrimBodySize, 
            TrError);
    }
  }
}

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

externCpp void 
bd93LogDelVarObj (
				  tbd_current_tree  &Current,
				  tgg92_KernelOid    OId, 
				  tgg91_PageRef      WantedObjVers,      //[inp]
				  tbd_nodeptr        pPage, 
				  tbd900_ObjFrame   *pObjFrame
				  )
{
	ROUTINE_DBG_MSP00 ("bd93LogDelVarObj");
	
  char buffer[8100];  // PTS 1121823

	/* This function writes the removing on var object into the log */
	
  /*  determine  pointer to the object body */
	cbd05_Current           ContObjCurrent;	
	cbd910_ContObjDataNode  NptrsBody (ContObjCurrent, nr_for_read);
	tbd900_VarObjBody      &VarObjBody    = *((tbd900_VarObjBody*) (pObjFrame->objBody_bd900));
	tsp00_Int4              ObjBodySize   = VarObjBody.vbdHeader_bd900.vhdObjSize_bd900;
	tsp00_Int4              ContObjFileNo = VarObjBody.vbdHeader_bd900.vhdContObjFileNo_bd900;
	tsp00_MoveObj          *pObjBody;
  const tsp00_Bool       &ObjectIsSplit = VarObjBody.vbdHeader_bd900.vhdObjectIsSplit_bd900; // PTS 1121823
	
  if (0==ContObjFileNo)
    // Object is completely stored in the primary container
		pObjBody = (tsp00_MoveObj*) VarObjBody.vbdBody_bd900;
	else if (!ObjectIsSplit)
	{
    // Object is completely stored in the continuation container
    const tsp00_PageNo     &ContObjPno = VarObjBody.vbdHeader_bd900.vhdContObjPno_bd900;
    const tgg00_ObjPagePos &ContObjPos = VarObjBody.vbdHeader_bd900.vhdContObjPos_bd900;
    bd93_GetContObjBodyPointer (Current, ContObjFileNo, ContObjPno, ContObjPos, OId,
                                m_select, ContObjCurrent,  NptrsBody, pObjBody);
	}
  else 
  {
    // Object is split across the primary and the continuation container (see PTS 1121823)

    const tgg00_ObjFileNo  ObjFileNo  = Current.curr_tree_id.fileObjFileNo_gg00(); 
    tsp00_Int4  PrimBodySize = bd90ObjFileDir[ObjFileNo].GetObjBodySize();

    // First read the portion stored in the primary container...
    pObjBody  = (tsp00_MoveObj*) VarObjBody.vbdBody_bd900;
    SAPDB_MemCopyNoCheck (&buffer[0], pObjBody, PrimBodySize);
   
    // ... then read portion stored in the continuation container and copy it
    // beyond the data of the primary container
		const tsp00_PageNo     &ContObjPno    = VarObjBody.vbdHeader_bd900.vhdContObjPno_bd900;
		const tgg00_ObjPagePos &ContObjPos    = VarObjBody.vbdHeader_bd900.vhdContObjPos_bd900;
			
    bd93_GetContObjBodyPointer (Current, ContObjFileNo, ContObjPno, ContObjPos, OId,
			                          m_select, ContObjCurrent, NptrsBody, pObjBody);

    SAPDB_MemCopyNoCheck (&buffer[PrimBodySize], pObjBody, ObjBodySize-PrimBodySize); 

    pObjBody = (tsp00_MoveObj*) &buffer[0];
  }
	
	/* check if object is locked and create a log entry  */ 
    
  kb67DelUpdObj (*Current.curr_trans, m_delete, Current.curr_tree_id,
        OId, pPage->nd_obj_key_len(), WantedObjVers,
        pObjFrame->objHeader_bd900, ObjBodySize, pObjBody);     
}

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

externCpp bool
bd93NextContObjBodyLen (tsp00_Int4  &ObjBodyLen)  // [inp/out]
{
	ROUTINE_DBG_MSP00 ("bd93NextContObjBodyLen");
	
	/* This function returns the ObjBodyLen which is about    */
	/* CONT_FRAME_ENLARGE_FACTOR_BD900 (in %) larger than the */
	/* input ObjBodyLen, fills the page as good as possible   */
	/* and is alligend                                        */
	
	double    LastOccupancy;
	double    LastLastOccupancy;
	double    Occupancy;
	int       iLen;
	int       StartSearchLen;
	int       r_ObjBodyLen;
	int       l_ObjBodyLen;
	bool      r_NextLenExists = false;
	bool      l_NextLenExists = false;
	const int MaxObjBodySize  = FULLCOVERING_BD00 - sizeof(tbd900_ContObjHeader);

	/* find the optimum size on the right side         */
	/* of ObjBodyLen * CONT_FRAME_ENLARGE_FACTOR_BD900 */ 
	LastOccupancy     = 0;
	LastLastOccupancy = 0;
	StartSearchLen    = (ObjBodyLen * CONT_FRAME_ENLARGE_FACTOR_BD900)/100;
	for (iLen=StartSearchLen-2; iLen<= MaxObjBodySize + 1; ++iLen)
	{
		Occupancy = bd93_OccupancyRate (iLen, NO_ALIGNMENT);	
		if((Occupancy < LastOccupancy) && (LastLastOccupancy < LastOccupancy))
		{
			r_NextLenExists = true;
			r_ObjBodyLen    = iLen-1;
			break;
		}
		LastLastOccupancy = LastOccupancy;
		LastOccupancy     = Occupancy;
	}

	/* align the the optimum object length */
	r_ObjBodyLen    = (r_ObjBodyLen/ALIGNMENT) * ALIGNMENT;
	if (r_ObjBodyLen <= ObjBodyLen) r_ObjBodyLen += ALIGNMENT;
	r_NextLenExists = r_NextLenExists && (r_ObjBodyLen > ObjBodyLen) && (r_ObjBodyLen <= MaxObjBodySize);

	
	/* find the optimum size on the left side          */
	/* of ObjBodyLen * CONT_FRAME_ENLARGE_FACTOR_BD900 */ 
	LastOccupancy     = 100.0;
	LastLastOccupancy = 100.0;
	StartSearchLen    = MIN_EO00 ((ObjBodyLen * CONT_FRAME_ENLARGE_FACTOR_BD900)/100, MaxObjBodySize);

	if (StartSearchLen > ObjBodyLen)
	{
		l_NextLenExists = true;
		l_ObjBodyLen    = StartSearchLen;
	}

	for (iLen=StartSearchLen+2; iLen> ObjBodyLen; iLen--)
	{
		Occupancy = bd93_OccupancyRate (iLen, NO_ALIGNMENT);
		if(Occupancy < LastOccupancy && LastLastOccupancy < LastOccupancy)
		{
			l_NextLenExists = true;
			l_ObjBodyLen    = iLen+1;
			break;
		}
		LastLastOccupancy = LastOccupancy;
		LastOccupancy     = Occupancy;
	}	
	
	/* align the the optimum object length */
    l_ObjBodyLen    = (l_ObjBodyLen/ALIGNMENT) * ALIGNMENT;
	l_NextLenExists = l_NextLenExists && (l_ObjBodyLen > ObjBodyLen);
	
	if (r_NextLenExists && ! l_NextLenExists)
		ObjBodyLen = r_ObjBodyLen;
	else
		if (!r_NextLenExists && l_NextLenExists)
			ObjBodyLen = l_ObjBodyLen;
		else
			if (r_NextLenExists && l_NextLenExists)
			{
				if (abs(l_ObjBodyLen - StartSearchLen) < abs (r_ObjBodyLen - StartSearchLen))
					ObjBodyLen = l_ObjBodyLen;
				else
					ObjBodyLen = r_ObjBodyLen;
			}

    return (l_NextLenExists || r_NextLenExists);
}

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

externCpp void
bd93RemoveContObj (
				  tbd_current_tree       &Current,        //[inp]
				  tgg92_KernelOid        &OId,            //[inp]    
				  const tsp00_Int4        ContObjFileNo,  //[inp]     
				  const tsp00_PageNo      ContObjPno,     //[inp] 
				  const tgg00_ObjPagePos  ContObjPos      //[inp]
				  )
{
	ROUTINE_DBG_MSP00 ("bd93RemoveContObj");
	
	/* This function removes an  continuation object */
	
	tgg00_BasisError      &TrError   = Current.curr_trans->trError_gg00;
	const tgg00_ObjFileNo  ObjFileNo = Current.curr_tree_id.fileObjFileNo_gg00(); //PTS 1111901 AK 24/09/2001

	/* construct currrent for the continuation objects */
	cbd05_Current ContCurrent (*Current.curr_trans, m_update);
	cbd900_ContObjFileInfo &ContObjFileInfo = bd93ContObjFileDir[ObjFileNo];
	ContObjFileInfo.bd900BuildFileId (ObjFileNo, ContObjFileNo, ContCurrent.curr_tree_id);
	
	/* get pointer to the page where the object is located */
	cbd910_ContObjDataNode  NptrsBody(ContCurrent, ContObjPno, nr_for_update);	                                                                  
	if (TrError != e_ok) return;

	const tsp00_Int2 ChainNo = NptrsBody.np_ptr()->nd_chain_no();

	/* release continuation object which is not used any more, the Nptrs are released too */
	bd93_ReleaseContObjFrame (ContCurrent, OId, NptrsBody, ContObjPos);
}

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

externCpp void
bd93UpdateVarObjBody (tbd_current_tree        &Current,
					  tgg92_KernelOid          OId,
					  tgg91_PageRef	           ObjVers,
					  cbd910_PrimObjDataNode  &NptrsAnchor,
					  tbd900_ObjFrame        *&pObjFrame, 
					  tsp00_Int4               NewObjBodySize,
					  void                    *pNewObjBody,
					  bool                     bRollBack,
					  bool                    &bNewContFileWasCreated,
					  bool                    &bTooManyEmptyPagesInContFile,
					  tsp00_Int4              &NewContObjFileNo,
					  tsp00_Int4              &ContObjFileNo,
					  tsp00_Int4              &ContObjChainNo,
					  const Log_EntrySequence &RedoEntrySequence,
			      const tgg91_TransNo     &RedoUpdTransNo)
{
	/* This function moves the object given by the pointer  */
	/* pNewObjBody into the object frame given by the OId   */

  char Buffer[8100];  // PTS 1121823

  tgg00_BasisError      &TrError    = Current.curr_trans->trError_gg00;
	const tgg00_ObjFileNo  ObjFileNo  = Current.curr_tree_id.fileObjFileNo_gg00(); //PTS 1111901 AK 24/09/2001
  bNewContFileWasCreated            = false;

	/* check frame state */
#   if COMPILEMODE_MEO00 >= QUICK_MEO00 
    if ((pObjFrame->objHeader_bd900.ohdState_gg92  != obsReserved_egg00   ) &&
        (pObjFrame->objHeader_bd900.ohdState_gg92  != obsOccupied_egg00   ))
    {   
        TrError = e_wrong_object_state;
        return;
    }
#   endif

	bool                     bMoveBodyToAnotherContFile = false;
  tsp00_Int4               MaxObjBodySize = 0;
  tsp00_Int4               MinObjBodySize = 0;
	tsp00_MoveObj           *pObjBody       = NULL;
	tsp00_MoveObj           *pOldObjBody    = NULL;

  cbd05_Current            ContObjCurrent;	
	cbd910_ContObjDataNode   NptrsBody (ContObjCurrent, nr_for_update);

  cbd900_ObjFileInfo      &ObjFileInfo     = bd90ObjFileDir[ObjFileNo];
	cbd900_ContObjFileInfo  &ContObjFileInfo = bd93ContObjFileDir[ObjFileNo];
  tbd900_VarObjBodyHeader *pHdr            = &(((tbd900_VarObjBody*) pObjFrame->objBody_bd900)->vbdHeader_bd900);
  tsp00_MoveObj           *pPrimBody       = (tsp00_MoveObj*) &(((tbd900_VarObjBody*) pObjFrame->objBody_bd900)->vbdBody_bd900);
  tsp00_Int4               PrimBodySize    = ObjFileInfo.GetObjBodySize();

  ContObjFileNo = pHdr->vhdContObjFileNo_bd900;

	if (PRIM_CONT_OBJ_FILE_NO_BD900 == pHdr->vhdContObjFileNo_bd900)
	{
    // Old object is stored completely in the primary container
		pObjBody       = pPrimBody;
		MaxObjBodySize = ObjFileInfo.GetObjBodySize();
		MinObjBodySize = 0;
	}
	else if (!pHdr->vhdObjectIsSplit_bd900)
	{
    // Old object is stored completely in the continuation container
		bd93_GetContObjBodyPointer (Current, 
      pHdr->vhdContObjFileNo_bd900, 
      pHdr->vhdContObjPno_bd900, 
      pHdr->vhdContObjPos_bd900, 
      OId, m_update, 
      ContObjCurrent, NptrsBody, pOldObjBody);
		if (TrError != e_ok) return;

		MaxObjBodySize =  ContObjFileInfo[pHdr->vhdContObjFileNo_bd900].GetObjBodySize();
		if (ContObjFileNo > 1)		
			//MinObjBodySize = (ContObjFileInfo[pHdr->vhdContObjFileNo_bd900-1].GetObjBodySize()*BALANCE_LIMIT_BD900)/100;
			MinObjBodySize = ContObjFileInfo[pHdr->vhdContObjFileNo_bd900-1].GetObjBodySize() + 1;
		else
			//MinObjBodySize = (ObjFileInfo.GetObjBodySize()*BALANCE_LIMIT_BD900)/100;
			MinObjBodySize = ObjFileInfo.GetObjBodySize() + 1;

		/* store current ChainNo, for a later call of the garbage collector */ 
    ContObjChainNo = NptrsBody.np_ptr()->nd_chain_no();

    pObjBody = pOldObjBody;  // PTS 1123494
	}
  else
  {
    // Old object is split across the primary and the continuation container.
    // Therefore the object must be merged. (PTS 1121823)

		bd93_GetContObjBodyPointer (Current, 
      pHdr->vhdContObjFileNo_bd900, 
      pHdr->vhdContObjPno_bd900, 
      pHdr->vhdContObjPos_bd900, 
      OId, m_update, 
      ContObjCurrent, NptrsBody, pOldObjBody);
		if (TrError != e_ok) return;

		MaxObjBodySize =  ContObjFileInfo[pHdr->vhdContObjFileNo_bd900].GetObjBodySize();
		if (pHdr->vhdContObjFileNo_bd900 > 1)		
			//MinObjBodySize = (ContObjFileInfo[pHdr->vhdContObjFileNo_bd900-1].GetObjBodySize()*BALANCE_LIMIT_BD900)/100;
			MinObjBodySize = ContObjFileInfo[pHdr->vhdContObjFileNo_bd900-1].GetObjBodySize() + 1;
		else
			//MinObjBodySize = (ObjFileInfo.GetObjBodySize()*BALANCE_LIMIT_BD900)/100;
			MinObjBodySize = ObjFileInfo.GetObjBodySize() + 1;

		/* store current ChainNo, for a later call of the garbage collector */ 
    ContObjChainNo = NptrsBody.np_ptr()->nd_chain_no();

    if (!bRollBack)
    {
      // First copy portion of primary container...
      SAPDB_MemCopyNoCheck(&Buffer[0], pPrimBody, PrimBodySize);

      // ...then copy portion of continuation container
      SAPDB_MemCopyNoCheck(&Buffer[PrimBodySize], pOldObjBody, pHdr->vhdObjSize_bd900 - PrimBodySize);

      pObjBody = (tsp00_MoveObj*) &Buffer[0];
    }
  }

	// find out where the new obj body has to be accomodated 
  // If the object fits into the primary container, the object is always (independend of
  // the setting of BALANCE_LIMIT_BD900) moved completely into the primary container
  NewContObjFileNo = pHdr->vhdContObjFileNo_bd900;
	if ((NewObjBodySize > MaxObjBodySize) || (NewObjBodySize < MinObjBodySize))
	{
		bMoveBodyToAnotherContFile = true;

    if (NewObjBodySize <= PrimBodySize)
      NewContObjFileNo = PRIM_CONT_OBJ_FILE_NO_BD900;	
    else if (NewObjBodySize <= 2*PrimBodySize)
      // Problem: If the remainder of the object (without the portion which is stored in
      //   the primary container is smaller than the upper bound for the primary container,
      //   then the following function would return the primary container.
      // Workaround: If the size is between PrimBodySize and 2*PrimBodySize, then the function
      //   is called with the original size. This prevent, that the primary container is returned
      bd93_FindFileNoForThisObjBodySize (NewObjBodySize, ObjFileNo, NewContObjFileNo, TrError);		
    else
      // Get a container which is large enough to store the remainder of the object
      bd93_FindFileNoForThisObjBodySize (NewObjBodySize-PrimBodySize, ObjFileNo, NewContObjFileNo, TrError);		
    if (TrError != e_ok) return;

		/* check if enough space is available */
		const tsp00_Int4 NumPagesProbablyNeeded = 1; 
		if (PRIM_CONT_OBJ_FILE_NO_BD900 != NewContObjFileNo)
		{
			Converter_IPageNoManager::Instance().HandleDBFull (*Current.curr_trans,	NumPagesProbablyNeeded);
		}
		if (TrError != e_ok) return;
	}
    
	if (!bRollBack)
  {
		/* update object transinfo and write a log entry */
		kb67UpdObj (*Current.curr_trans, Current.curr_tree_id,
			OId, NptrsAnchor.np_ptr()->nd_obj_key_len(), ObjVers,
			pObjFrame->objHeader_bd900, pHdr->vhdObjSize_bd900, pObjBody,
			RedoEntrySequence, RedoUpdTransNo);		
    if (TrError != e_ok) return;
  }

  if (PRIM_CONT_OBJ_FILE_NO_BD900 == NewContObjFileNo)
	{
	  if (bMoveBodyToAnotherContFile)
		{
			/* release the current body frame and page pointer     */ 
			bd93_ReleaseContObjFrame (ContObjCurrent, OId, NptrsBody, pHdr->vhdContObjPos_bd900);

      // Reset pointer to continuation container
		  pHdr->vhdContObjFileNo_bd900 = PRIM_CONT_OBJ_FILE_NO_BD900;
			pHdr->vhdContObjPno_bd900    = NIL_PAGE_NO_GG00;
			pHdr->vhdContObjPos_bd900    = NIL_OBJ_PAGE_POS_GG92;
		}

	  // update var object header 
	  pHdr->vhdObjSize_bd900       = NewObjBodySize;
	  pHdr->vhdObjectIsSplit_bd900 = false;  // PTS 1121823
	
      if ( NewObjBodySize > 0 )
      {
          
          // update object in primary container
          SAPDB_RangeMove( __FILE__, 31,
              NewObjBodySize,  ObjFileInfo.GetObjBodySize(), 
              pNewObjBody,  1, 
              pPrimBody,    1,
              NewObjBodySize,  
              TrError); 
      }
  }
  else
	{
    // First update data in primary container
	  SAPDB_RangeMove( __FILE__, 32,
		  PrimBodySize,  ObjFileInfo.GetObjBodySize(), 
		  pNewObjBody, 1, 
      pPrimBody,   1,
		  PrimBodySize,  
      TrError); 

    // Update data in continuation container
    if (bMoveBodyToAnotherContFile)
    {
			/* release the current body frame and page pointer     */ 
			if (PRIM_CONT_OBJ_FILE_NO_BD900 != pHdr->vhdContObjFileNo_bd900)
				bd93_ReleaseContObjFrame (ContObjCurrent, OId, NptrsBody, pHdr->vhdContObjPos_bd900);
			
			/* get a new object frame of an appropriate length */
			bd93_NewContObj (Current, NewContObjFileNo, OId, ContObjFileInfo, 
				ContObjCurrent, NptrsBody, pHdr->vhdContObjPos_bd900, bNewContFileWasCreated);
			if (TrError != e_ok) return;
			
	    /* update var object header */
			pHdr->vhdContObjPno_bd900    = NptrsBody.np_ptr()->nd_id();
			//pHdr->vhdContObjPos_bd900  = ;  // changed already by call of bd93_NewContObj
		  pHdr->vhdContObjFileNo_bd900 = NewContObjFileNo;

      // Get pointer to new destination
			const tbd900_ContObjFrame *pContObjFrame = (tbd900_ContObjFrame *) ((char*) NptrsBody.np_ptr() + pHdr->vhdContObjPos_bd900);
      pObjBody       = (tsp00_MoveObj *) (pContObjFrame->cofBody_bd900);
			MaxObjBodySize = ContObjFileInfo[NewContObjFileNo].GetObjBodySize();
		}
    else
    {
      // Get pointer to old destination
		  pObjBody = pOldObjBody;
			MaxObjBodySize = ContObjFileInfo[pHdr->vhdContObjFileNo_bd900].GetObjBodySize();
    }
		
    // Update header
		pHdr->vhdObjectIsSplit_bd900 = true;   // PTS 1121823
	  pHdr->vhdObjSize_bd900       = NewObjBodySize;
	
	  // Update object
	  SAPDB_RangeMove( __FILE__, 33,
		  NewObjBodySize-PrimBodySize,  MaxObjBodySize, 
		  (tsp00_MoveObj*) pNewObjBody + PrimBodySize, 1, 
      pObjBody,                                    1,
		  NewObjBodySize-PrimBodySize,  
      TrError); 
	}
}

/*===========================================================================*
 *  LOCAL FUNCTIONS (CODE)                                                   *
 *===========================================================================*/
				 
static _INLINE void
bd93_CheckContObjRoot (
					   const tgg92_KernelOid      &RootOId,         //[inp] 
					   const tbd900_ContObjHeader &ContObjHeader    //[inp]
					   )
{
	ROUTINE_DBG_MSP00 ("bd93_CheckContObjRoot");
	
	/* This function checks if the given RootOid is really */ 
	/* the root of the given continuation object frame     */ 	
	
	if ((RootOId.gg92GetPos()  != ContObjHeader.cvoRootOIdPos_bd900) ||
		(RootOId.gg92GetPno()  != ContObjHeader.cvoRootOIdPno_bd900) ||
		(NIL_OBJ_PAGE_POS_GG92 != ContObjHeader.cvoNextFreeObj_bd900))
	{
		/* report error in knldiag and vtrace */
		g01optextmsg (sp3p_knldiag, sp3m_error, csp3_bd_msg, csp3_n_obj, 
			"BD93_Check: RootOId <> ContObj.RootOId  ");
		
		g01opmsg (sp3p_knldiag, sp3m_error, csp3_bd_msg, csp3_n_obj, 
			"           RootOId.Page=", RootOId.gg92GetPno() );
		g01opmsg (sp3p_knldiag, sp3m_error, csp3_bd_msg, csp3_n_obj, 
			"   ContObj.RootOId.Page=",  ContObjHeader.cvoRootOIdPno_bd900);
		g01opmsg (sp3p_knldiag, sp3m_error, csp3_bd_msg, csp3_n_obj, 
			"            RootOId.Pos=", RootOId.gg92GetPos() );
		g01opmsg (sp3p_knldiag, sp3m_error, csp3_bd_msg, csp3_n_obj, 
			"    ContObj.RootOId.Pos=", ContObjHeader.cvoRootOIdPos_bd900);
		g01opmsg (sp3p_knldiag, sp3m_error, csp3_bd_msg, csp3_n_obj, 
			"  ContObj.RootOId.NextF=", ContObjHeader.cvoRootOIdPos_bd900);
	}
}

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

_INLINE static void
bd93_FindFileNoForThisObjBodySize (const tsp00_Uint4      NewObjBodySize, //[inp]  
								   const tgg00_ObjFileNo  ObjFileNo,      //[inp] 
								   tsp00_Int4            &ContFileNo,     //[out]
								   tgg00_BasisError      &TrError)        //[out]
{
	ROUTINE_DBG_MSP00 ("bd93_FindFileNoForNewBody");
	
	/* This function determines the number of the file which has the right  */
	/* object frames to accomodate objects of the given size NewObjBodySize */
	
    /* check if the object fits into the primary var object file */
	if (NewObjBodySize <= bd90ObjFileDir[ObjFileNo].GetObjBodySize())
	{
		ContFileNo = PRIM_CONT_OBJ_FILE_NO_BD900;
		return;
	}
	else
	{
		/* find the suiting continuation file */
		cbd900_ContObjFileInfo & ContObjFileInfo = bd93ContObjFileDir[ObjFileNo];

		/* check if there really exists an entry in the continuation file directory */
#       if COMPILEMODE_MEO00 >= QUICK_MEO00 
		if (ContObjFileInfo.cfiNumContFiles_bd900 <1)
			g01abort (csp3_bd_msg, csp3_n_obj, "BD93_FindFileNo:No Entry", ObjFileNo);
#       endif

	         	ContFileNo = (ContObjFileInfo.cfiNumContFiles_bd900+1)/2;
		bool        bFound = false;	
		tsp00_Int4  Delta  = ContFileNo;
		
		do
		{   
			if (NewObjBodySize <= ContObjFileInfo[ContFileNo].GetObjBodySize())
			{
				if ((ContFileNo==1) ||
					(NewObjBodySize > ContObjFileInfo[ContFileNo-1].GetObjBodySize()))
				{
					bFound = true;
				}
				else
				{
					Delta       = (Delta+1)/2;
					ContFileNo -=  Delta;
				}
			}
			else
			{
				Delta       = (Delta+1)/2;
				ContFileNo +=  Delta;
				if (ContFileNo > ContObjFileInfo.cfiNumContFiles_bd900)
				{
					g01opmsg (sp3p_knldiag, sp3m_error, csp3_bd_msg, csp3_n_obj, 
						"BD93_Find:WrongVarObjLen", NewObjBodySize);
					TrError = e_illegal_object_length;
					return;
				}
			}
		}
		while (!bFound);
	}
}
		
		
/*---------------------------------------------------------------------------*/

_INLINE static void
bd93_GetContObjBodyPointer (
    					tbd_current_tree       &Current,         //[inp/out]
						const tsp00_Int4        ContObjFileNo,   //[inp]     
						const tsp00_PageNo      ContObjPno,      //[inp] 
						const tgg00_ObjPagePos  ContObjPos ,     //[inp]
						const tgg92_KernelOid  &OId,             //[inp] 
						tgg00_MessType_Enum     MessType,        //[inp]
						cbd05_Current          &ContCurrent,     //[out]
						cbd910_ContObjDataNode &NptrsBody,       //[out]
						tsp00_MoveObjPtr       &pObjBody         //[out]
					   )
{
	ROUTINE_DBG_MSP00 ("bd93_GetContObjBodyPointer");
	
	/* this function supplies the pointer to an continuation object body     */
	/* which is derived from the page number and page position of the object */
	
	tbd900_ContObjFrame     *pContObjFrame; 
	tgg00_BasisError        &TrError   = Current.curr_trans->trError_gg00;
	const tgg00_ObjFileNo    ObjFileNo = Current.curr_tree_id.fileObjFileNo_gg00(); //PTS 1111901 AK 24/09/2001
	tgg00_FileId             ObjFileId;	
    cbd900_ContObjFileInfo  &ContObjFileInfo = bd93ContObjFileDir[ObjFileNo]; 

    ContObjFileInfo.bd900BuildFileId(ObjFileNo, ContObjFileNo, ObjFileId);

    /* construct currrent for the continuation objects */
    ContCurrent.bd05SetCurrent (*Current.curr_trans, MessType,  ObjFileId);

	/* get page pointer */
	NptrsBody.bd910AssignToPage (ContObjPno);
	if (TrError != e_ok) return;
	
	/* get object pointer */
	pContObjFrame = (tbd900_ContObjFrame *) ((char*) NptrsBody.np_ptr() + ContObjPos);
	pObjBody      = (tsp00_MoveObj *) (pContObjFrame->cofBody_bd900);
	
	/* check if the found object frame belongs to the root OId */
	if (g01vtrace.vtrCheck_gg00)
        bd93_CheckContObjRoot (OId, pContObjFrame->cofHeader_bd900); 
}

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

static void 
bd93_NewContObj (tbd_current_tree        &Current,                 // [inp]
				 tsp00_Int4               ContFileNo,              // [inp]
				 const tgg92_KernelOid   &RootOId,                 // [inp] 
				 cbd900_ContObjFileInfo  &ContObjFileInfo,         // [inp]
				 cbd05_Current           &ContCurrent,             // [out]
				 cbd910_ContObjDataNode  &NptrsBody,               // [out]
				 tgg00_ObjPagePos        &ContObjPos,              // [out]
				 bool                    &bNewContFileWasCreated)  // [out]
{
    ROUTINE_DBG_MSP00 ("bd93_NewContObj");
    
    /* This function yields a new continuation object frame */
	/* which is identified by ContObjPno and ContObjPos     */
    /* The new frame is searched in the the free chain.     */
	
    tgg00_BasisError      &TrError      = Current.curr_trans->trError_gg00;
	const tgg00_ObjFileNo  ObjFileNo    = Current.curr_tree_id.fileObjFileNo_gg00(); 
	/*cbd900_ObjFileInfo    &ObjFileInfo  = ContObjFileInfo[ContFileNo];            PTS 1127279 FF 2004-01-26  */
	tgg00_FileId           ObjFileId;
	
	/* construct currrent for the continuation objects */	
    ContObjFileInfo.bd900BuildFileId(ObjFileNo, ContFileNo, ObjFileId);
    ContCurrent.bd05SetCurrent (*Current.curr_trans, m_update, ObjFileId);
	
	/* check if the new continuation file exists already  */
	/* if the file does not exist so far create it        */
	if (NIL_PAGE_NO_GG00 != ContObjFileInfo[ContFileNo].GetRootPage())
		bNewContFileWasCreated = false;
	else
	{
        /* PTS 1127279 FF 2004-01-26                                  */
        /* use region to avoid the continous file to be created twice */
        vbegexcl (Current.curr_trans->trTaskId_gg00, g08objcontf); 
        if (NIL_PAGE_NO_GG00 != ContObjFileInfo[ContFileNo].GetRootPage())
            bNewContFileWasCreated = false;
        else
        {						
            const int cZeroKeyLen          = 0;
            const int MaxObjBodySize       = ContObjFileInfo[ContFileNo].GetObjBodySize();
            const tsp00_Bool cNoObjKeyFile = false;
            bNewContFileWasCreated         = true;
            LVC_RootPageNoArray DummyRootPageNoArray;

            bd90CreateObjFile (ContCurrent, MaxObjBodySize, cZeroKeyLen, cNoObjKeyFile, DummyRootPageNoArray);

            if (e_ok == TrError)
                bd90CreateEntryInPersFileDirectory (ContCurrent);
            else
            {
                if (e_duplicate_filename == TrError)
                    TrError = e_ok;
                else
                {
                    Kernel_OpError( csp3_bd_msg, csp3_n_obj ) << __FILE__ << " : " << __LINE__ 
                        << " TrError:" << TrError
                        << " FileNo:" << ObjFileNo
                        << " ContFileNo:" << ContFileNo;
                    if ((g01vtrace.vtrBdObject_gg00) || (g01vtrace.vtrOmsUpd_gg00 ))
                    {
                        Kernel_VTrace() << __FILE__ << " : " << __LINE__ 
                            << " TrError:" << TrError
                            << " FileNo:" << ObjFileNo
                            << " ContFileNo:" << ContFileNo;
                    }
                    vendexcl (Current.curr_trans->trTaskId_gg00, g08objcontf); /* PTS 1127279 FF 2004-01-26 */
                    return;
                }
            }	
        }
        vendexcl (Current.curr_trans->trTaskId_gg00, g08objcontf); /* PTS 1127279 FF 2004-01-26 */
    }

	/* get handle for the current subroot */
	cbd900_ObjFileInfo    &ObjFileInfo     = ContObjFileInfo[ContFileNo];
	const tsp00_Int4            ChainNo    = ObjFileInfo.bd900CurrChain();
          cbd900_ObjChainInfo  &ChainInfo  = ObjFileInfo[ChainNo];
    const tsp00_PageNo          SubRoot    = ChainInfo.ociSubRoot_bd900; 
    cbd910_SubRootNode   NptrsSubRoot (ContCurrent, SubRoot, nr_for_update);
    if (TrError != e_ok) 
    {
        Kernel_OpError( csp3_bd_msg, csp3_n_obj ) << __FILE__ << " : " << __LINE__ 
            << " TrError:" << TrError
            << " FileNo:" << ObjFileNo
            << " ContFileNo:" << ContFileNo
            << " Root:" << ObjFileInfo.GetRootPage()
            << " SubRoot:" << SubRoot;
        if ((g01vtrace.vtrBdObject_gg00) || (g01vtrace.vtrOmsUpd_gg00 ))
        {
            Kernel_VTrace() << __FILE__ << " : " << __LINE__ 
                << " TrError:" << TrError
                << " FileNo:" << ObjFileNo
                << " ContFileNo:" << ContFileNo
                << " Root:" << ObjFileInfo.GetRootPage()
                << " SubRoot:" << SubRoot;
        }
        return;
    }
	
#   if COMPILEMODE_MEO00 >= QUICK_MEO00 
	/* check if this subroot page belongs really to this file */
	if ((NptrsSubRoot.np_ptr()->nd_root()        != ObjFileInfo.GetRootPage()) || 
		(NptrsSubRoot.np_ptr()->nd_obj_file_no() != ObjFileNo)                 ||
		(NptrsSubRoot.np_ptr()->nd_sub_root()    != SubRoot)                   ||
		(NptrsSubRoot.np_ptr()->nd_chain_no()    != ChainNo))
	{
		g01abort (csp3_bd_msg, csp3_n_obj, 
			"BD93_NewObj:wrong SRoot ", NptrsSubRoot.np_ptr()->nd_id());
    }
#   endif

	/* get page handle for the first page with free objects */
	/* CRS 1106534 Alexander Kley 2000-05-11                */
#   ifdef STORE_OBJECTS_ON_SUBROOT_BD900	 
	if (NptrsSubRoot.np_ptr()->nd_free_obj_cnt() > 0)
		NptrsBody.bd910SetTo (NptrsSubRoot, true /*movePrimary PTS 1130598*/);
	else
#   endif
	{
		if (NIL_PAGE_NO_GG00 != NptrsSubRoot.np_ptr()->nd_next_free())
			NptrsBody.bd910AssignToPage (NptrsSubRoot.np_ptr()->nd_next_free());
		else
			NptrsBody.bd910AssignToNewPageInDataChain (NptrsSubRoot, false /*insert into freelist*/);
		if (e_ok != TrError) return;
	}
	
	/* get a new OId and initialize the corresponding object */
	bd93_NewContObjFromThisPage (ContCurrent, NptrsBody, RootOId, ContObjPos);
    if (e_ok != TrError) return;

	/* remove page from free page chain if there are no more free object frame on the page */
    NptrsSubRoot.bd910RestoreFreePageChain (NptrsBody, ChainInfo); 
}

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

_INLINE static void 
bd93_NewContObjFromThisPage (tbd_current_tree        &Current,                  // [inp]
							 cbd910_ContObjDataNode  &NptrsBody,                // [inp]
							 const tgg92_KernelOid   &RootOId,                  // [inp]
							 tgg00_ObjPagePos        &ContObjPos)               // [out]  
{
	ROUTINE_DBG_MSP00 ("bd93_NewContObjFromThisPage");
	
	/*  This routine finds a free frame on a page presuming that at least one free  */
	/*  object frame exists. Moreover all pointers are restored corresponding       */
	/*  to changing the state of the frame whichs OId is returned                   */
	
	tbd900_ContObjFrame   *pContObjFrame; 
	tgg00_BasisError      &TrError   = Current.curr_trans->trError_gg00;
    tbd_nodeptr           &pPage     = NptrsBody.np_ptr();
	
    /* (PTS 1134505) check if the position of the first free obj is valid   */
    if ( !bd92ObjPosIsValid (pPage->nd_first_free_obj(), pPage->nd_first_obj(), pPage->nd_obj_frame_len()))
    {
        Kernel_OpError ( csp3_bd_msg, csp3_n_obj ) << __FILE__ << ":" << __LINE__
            << " wrong position: " << pPage->nd_first_free_obj()
            << " page:" << pPage->nd_id()
            << " first free pos: " << pPage->nd_first_free_obj()
            << " page dumped into: d" 
            << pPage->nd_id() << ".obj"; 
        b06dump_bad_page (Current.curr_trans->trTaskId_gg00,'d', ".obj", pPage->nd_id(), 
            (void *) NptrsBody.np_ptr(), 1);

        if ( bd92ObjPosIsValid (pPage->nd_first_free_obj(), pPage->nd_first_obj(), pPage->nd_obj_frame_len()))
            TrError = e_wrong_object_state;
        else
            TrError = e_illegal_object_pos;
        return;
    }
 	
	/*  construct position of the object frame  header             */
	pContObjFrame = (tbd900_ContObjFrame *)	((char*) pPage + pPage->nd_first_free_obj());
	
	/*  get position of free object frame */
	ContObjPos   = pPage->nd_first_free_obj();
	
	/*  update page header */
	--pPage->nd_free_obj_cnt();
	++pPage->nd_occ_obj_cnt();
	pPage->nd_first_free_obj() = pContObjFrame->cofHeader_bd900.cvoNextFreeObj_bd900;
	
	/*  update object frame header */
	pContObjFrame->cofHeader_bd900.cvoNextFreeObj_bd900 = NIL_OBJ_PAGE_POS_GG92;
	pContObjFrame->cofHeader_bd900.cvoRootOIdPno_bd900  = RootOId.gg92GetPno();
	pContObjFrame->cofHeader_bd900.cvoRootOIdPos_bd900  = RootOId.gg92GetPos();
	
	/*   initialize the object body, i.e. the first four bytes     */
	/*   of the body are filled with hex zeros and the body header */
	/*   of variable length objects are initialized                */
	const int  MaxObjBodySize = pPage->nd_obj_frame_len() - sizeof (tbd900_ContObjHeader);
	char       InitString[5]  = "\x00\x00\x00\x00";
	SAPDB_MemCopyNoCheck (pContObjFrame->cofBody_bd900, InitString, MIN_EO00 (4,MaxObjBodySize)); 

	/* increase global counter of used object frames in the current chain */   
	const tsp00_Int4  ContObjFileNo  = Current.curr_tree_id.fileContObjFileNo_gg00();
	const tsp00_Int2 &ChainNo        = pPage->nd_chain_no();
};

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

_INLINE static double
bd93_OccupancyRate (int ObjBodyLen,
					int Alignment)
{
	ROUTINE_DBG_MSP00 ("bd93_OccupancyRate");

	/* this function returns the occupancy rate of an object page  */
	/* occupied with continuation objects of the length ObjBodylen */
	/* The calculation considers the  alignment                    */ 

	const int ObjDistance = (((sizeof(tbd900_ContObjHeader)+ObjBodyLen-1)/Alignment)+1)*Alignment; 
	const int NumObj      = FULLCOVERING_BD00/ObjDistance;	
	return ((100.0*NumObj*ObjBodyLen)/FULLCOVERING_BD00);
}

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

_INLINE static void
bd93_ReleaseContObjFrame (tbd_current_tree       &Current,
						  const tgg92_KernelOid  &OId,            
						  cbd910_ContObjDataNode &NptrsContObjPage,
						  const tgg00_ObjPagePos  ContObjPos)
{
	ROUTINE_DBG_MSP00 ("bd93_ReleaseContObjFrame");
	
	/* release an  continuation object, i.e. change its    */
	/* state to free and introduce the frame into the free */
	/* frame chain. Moreover the page pointer is released  */

	tbd_nodeptr           &pContObjPage = NptrsContObjPage.np_ptr(); 
    tgg00_BasisError      &TrError      = Current.curr_trans->trError_gg00;
	const tgg00_ObjFileNo  ObjFileNo    = Current.curr_tree_id.fileObjFileNo_gg00();

    /* get pointer to subroot page */	
	cbd910_SubRootNode   NptrsSubRoot (Current, nr_for_update);  

	if ( NptrsContObjPage.bd910LockSubRootBeforeReleasingFrame() ) 
    {
        NptrsSubRoot.bd910AssignToSubroot (NptrsContObjPage);
		if (e_ok != TrError) 
		{
			/* check if the error is due to a drop of the file */
			if ((e_page_in_wrong_tree == TrError) || (e_no_converter_entry == TrError))
			{
				if ((NIL_PAGE_NO_GG00 == bd90ObjFileDir[ObjFileNo].GetRootPage()) ||
					(bd90ObjFileDir[ObjFileNo].ofiRelFileIsReq_bd900))
				{
					TrError = e_ok;
				}
                return;
            }
        }

        /* check if chaining will still be needed ( meahnwhile the page may have changed a lot */
		if ( !NptrsContObjPage.bd910LockSubRootBeforeReleasingFrame() ) 
		{	
			/* no chaining will be needed anymore ==> release subroot */
			NptrsSubRoot.bd910ReleasePage();
		}
    }


	/* get pointer to the continuation object */	
	tbd900_ContObjHeader & ContObjHeader  = *(tbd900_ContObjHeader *) ((char *) pContObjPage+ContObjPos);

	/* check if the found object frame belongs to the root OId */
	if (g01vtrace.vtrCheck_gg00)
		bd93_CheckContObjRoot (OId, ContObjHeader); 

	/* insert object frame into chain of free frames	*/	
	ContObjHeader.cvoNextFreeObj_bd900 = pContObjPage->nd_first_free_obj();
	pContObjPage->nd_first_free_obj()  = ContObjPos;

	/* reset frame header */
	ContObjHeader.cvoRootOIdPno_bd900 = NIL_PAGE_NO_GG00;
    ContObjHeader.cvoRootOIdPos_bd900 = NIL_OBJ_PAGE_POS_GG92;

	/* update page header */  
	++pContObjPage->nd_free_obj_cnt();
    --pContObjPage->nd_occ_obj_cnt();

	/* update global counter of all objects */
	const tsp00_Int4 ContObjFileNo  = Current.curr_tree_id.fileContObjFileNo_gg00();
	const tsp00_Int2 &ChainNo       = pContObjPage->nd_chain_no();
    cbd900_ObjChainInfo  &ChainInfo = bd93ContObjFileDir[ObjFileNo][ContObjFileNo][ChainNo];
	ChainInfo.DecrementAllObjCnt();

#   if COMPILEMODE_MEO00 >= SLOW_MEO00 
    // check if the number of objects is within reasonable limits  
	if((0>ChainInfo.GetAllObjCnt()) ||
		(ChainInfo.GetAllObjCnt() >
		ChainInfo.ociAllPageCnt_bd900 * bd93ContObjFileDir[ObjFileNo][ContObjFileNo].GetObjPerPageCount()))
	{
		g01opmsg (sp3p_knldiag, sp3m_error, csp3_bd_msg, csp3_n_obj, 
			"bd93RelCon:odd AllObjCnt",	ChainInfo.GetAllObjCnt() );
	}
#   endif
	
    
    /*--------------------------------------------------------------------*/
    /* if the page becomes an empty page by removing the object it is     */ 
    /* released                                                           */
    /*--------------------------------------------------------------------*/
    if ( NptrsContObjPage.bd910IsEmptyPage())
    {
        /* bd910RemovePageFromChainOfAllPages will release subroot PTS 1135421 */
        NptrsSubRoot.bd910RemovePageFromChainOfAllPages(NptrsContObjPage);         
    }
    else 
    {
        /* update free chain and free page counter */ 
        if (NptrsContObjPage.bd910PageMustBeInsertedIntoFreeChain())
        {	
            NptrsSubRoot.bd910InsertPageIntoFreeChain (NptrsContObjPage);    
            
            /* refresh the counter of used objects on the subroot. Note; that                 */
            /* ociAllObjCnt_bd900 is updated  dirty and need not be correct.Here it is tried  */
            /* to keep the trivial restriction that the number of all objects must be >=0     */
            cbd900_SubRootPageInfo  SubRootPageInfo (NptrsSubRoot);
            SubRootPageInfo.bd900AllObjCnt() = SAPDB_MAX (ChainInfo.GetAllObjCnt(), 0);
        }    
        
        /* release pointer to continuation page */
        NptrsContObjPage.bd910ReleasePage();
    }
}

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