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

  module        : gbd600.h
  special area  : Node Handling
  see also      : example.html ...
  responsible   : UweH
  last changed  : 1999-09-03  15:46
  copyright     : (c) 1999-2004 SAP AG
  implementation: vbd600.cpp, vbd610.cpp, vbd620.cpp
  description   : defines class cbd600_Node



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

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

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

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


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


#ifndef GBD600_H
#define GBD600_H

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

#include "gsp00.h"
#include "ggg00.h"
#include "gbd00.h"
#include "gsp03.h"
#include "gsp03_3.h"
#include "hgg10.h"

#include "gbd300.h"
#include "hbd13.h"
#include "hgg01_1.h"

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

/*===========================================================================*
 *  FORWARD DECLARATIONS                                                     *
 *===========================================================================*/

class cbd500_Tree;
class cbd500_SubTree;
class cbd800_PrimaryTree;

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

#define UNDER_FLOW_LIMIT_BD600 HALF_COVERING_BD00
#define IS_CHANGED_BD600       true

#define IS_LEFT_NODE_GBD600    true
#define IS_RIGHT_NODE_GBD600   false

#define TRUE                   1

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

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

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

/*---------------------------------------------------------------------------*/
/*!
    class:       cbd600_Node
    description: methodes to handle Node-Pages
*/

class cbd600_Node
{
	friend class cbd500_Tree;
	friend class cbd500_SubTree;
	friend class cbd800_PrimaryTree;
	friend class cbd400_InvTree;
public:
    /*!
    function:    cbd600_Node
    description: copy constructor.
    arguments:   Node [in]    Node to copy.
    */
	cbd600_Node (const cbd600_Node &Node);

    /*!
    function:    cbd600_Node
    description: this is for accessing the root node.
    arguments:   Current       [in/out] for TrError, TaskID.
                 PageLockMode  [in]     How the Page of the node is locked. (default = CacheLock)
    */
	cbd600_Node (cbd300_InvCurrentBasis   &Current,
		         const tbd00_PageLockMode &PageLockMode = tbd00_PageLockMode::fromConst(plmLock_ebd00));
    /*!
    function:    cbd600_Node
    description: This constructs an empty node, which can be used to access any node.
    arguments:   Current       [in/out] for TrError, TaskID.
                 RequestKind   [in]     How pages are requested from the Datacache (for_read/for_update)
                 PageLockMode  [in]     How the Page of the node is locked. (default = CacheLock)
    */
	cbd600_Node (cbd300_InvCurrentBasis   &Current,
		         const tbd_node_request   &RequestKind,
		         const tbd00_PageLockMode &PageLockMode = tbd00_PageLockMode::fromConst(plmLock_ebd00));
    /*!
    function:    cbd600_Node
    description: create a nodehandle and get specified page.
    arguments:   Current       [in/out] for TrError, TaskID.
                 RequestKind   [in]     How pages are requested from the Datacache (for_read/for_update)
                 Pno           [in]     Page Number
                 PageLockMode  [in]     How the Page of the node is locked. (default = CacheLock)
    */
	cbd600_Node (cbd300_InvCurrentBasis   &Current,
		         const tbd_node_request   &RequestKind,
				 tsp00_PageNo              Pno,
		         const tbd00_PageLockMode &PageLockMode = tbd00_PageLockMode::fromConst(plmLock_ebd00));
    /*!
    function:    cbd600_Node
    description: create a nodehandle and use the given CacheHandle NPTR.
    arguments:   Current       [in/out] for TrError, TaskID.
                 RequestKind   [in]     How pages are requested from the Datacache (for_read/for_update)
                 Nptr          [in/out] DataCacheHandle
                 PageLockMode  [in]     How the Page of the node is locked. (default = CacheLock)
    */
	cbd600_Node (cbd300_InvCurrentBasis   &Current,
		         const tbd_node_request   &RequestKind,
				 tbd_node_ptrs            &Nptr,
		         const tbd00_PageLockMode &PageLockMode = tbd00_PageLockMode::fromConst(plmLock_ebd00));
    /*!
    function:    cbd600_Node
    description: create a nodehandle and use the given buffer, no DataCache is used.
    arguments:   Current       [in/out] for TrError, TaskID.
                 Buffer        [in/out] Node Buffer
                 PageLockMode  [in]     How the Page of the node is locked. (default = CacheLock)
    */
	cbd600_Node (cbd300_InvCurrentBasis   &Current,
		         tbd_node                 &Buffer,
		         const tbd00_PageLockMode &PageLockMode = tbd00_PageLockMode::fromConst(plmLock_ebd00));
    /*!
    function:    ~cbd600_Node
    description: releases the DataCache Page if there is one, checks, if updated
    */
	~cbd600_Node ();
    /*!
    function:    bd600AddRecordSpace
    description: Given length is reserved in the page, at the given position, if there
                 is not enough space e_no_more_space is set.
    arguments:   RequiredLen [in]  Total record length
                 RecIndex    [in]  position, where the new record must be inserted
                 pRec        [out] Points to the ByteString, where the requested space is available
    */
	void              bd600AddRecordSpace    (tsp00_Int4    RequiredLen,
									          tsp00_Int4    RecIndex,
										      tgg00_RecPtr &pRec);
    /*!
    function:    bd600BuildSeparatorKey
    */
	void              bd600BuildSeparatorKey (cbd600_Node  &RightNeighbor,
								              tsp00_KeyPtr &pSepKey,
								              tsp00_Int2   &SepKeyLen) const;
    /*!
    function:    bd600BuildSeparatorKey
    */
	void              bd600BuildSeparatorKey (bool          bNodeIsLeft,
								              tsp00_KeyPtr  pNeighborKey,
                                              tsp00_Int4    NeighborKeyLen,
                                              tsp00_KeyPtr &pNewSepKey,
                                              tsp00_Int2   &NewSepKeyLen) const;
    /*!
    function:    bd600Check
    */
    void              bd600Check             (const bool bWithExtendedCheck) const;
    void              bd600CheckWithErrorHandling() const;
	void              bd600CheckIndex        () const;
	void              bd600CopyBody          (cbd600_Node &SrcNode);
	void              bd600CountRecords      (tsp00_KeyPtr  pStartKey, 
		                                      tsp00_Int4    StartKeyLen, 
										      tsp00_KeyPtr  pStopKey,
										      tsp00_Int4    StopKeyLen,
		                                      tsp00_Int4   &RecordCnt) const;
	tsp00_Int4        bd600Covering          () const;
	void              bd600DelRecordSpace    (tsp00_Int4 RecIndex);
	void              bd600Dump              (tsp00_Int4 ErrorId, const char *MsgText /*tsp00_C24*/) const;
    void              bd600EvalSepKeyLen     (tsp00_KeyPtr pKey,
							                  tsp00_Int4   KeyLen,
							                  tsp00_KeyPtr pNewSepKey,
							                  tsp00_Int2   &NewSepKeyLen) const;
	void              bd600Exchange          (cbd600_Node &Neighbor);
	void              bd600Free              ();
    tsp00_PageNo      bd600GetId             () const;
    tsp00_Int4        bd600PageConverterVersion () const;
    tbd_nodeptr       bd600GetNodePtr        ();
    void              bd600GetNode           (tsp00_PageNo            PageNo,
					 			              const tbd_node_request &RequestKind);
    void              bd600GetNode           (tsp00_PageNo PageNo);
    void              bd600GetStatistic      (tgg00_SampleInfo  &Info,
							                  tbd_stat_aux_vars &StatAuxVars,
							                  bool               bWithSelectivity) const;
	bool              bd600IsAccessable      () const;
    bool              bd600IsLeaf            () const;
    bool              bd600IsRoot            () const;
    bool              bd600IsUpdateable      () const;
	tsp00_Int4       &bd600LeafCount         ();
	tsp00_Int4        bd600LeafCount         (const tsp00_Int4 StartRecIndex,
		                                      const tsp00_Int4 StopRecIndex) const;
    tsp00_Int4   	  bd600Level             () const;
	tsp00_PageNo      bd600RightNeighbor     () const;
	tsp00_Int4   	  bd600MaxRecIndex       () const;
    void              bd600Move              (tsp00_PageNo NewId);
	void			  bd600New               (tsp00_Int4 Level);
    tgg00_RecPtr      bd600NewRecPtr         ();
	bool              bd600NodeIsRequested   () const; 
	tsp00_Int4        bd600NumRecords        () const;
    tsp00_Int4        bd600PrimKeyCount      (const tsp00_Int4 StartRecIndex, 
						                      const tsp00_Int4 StopRecIndex) const;
	tgg00_RecPtr      bd600RecPtr            (tsp00_Int4 RecIndex) const;
    void              bd600Release           (bool IsChanged);
	void              bd600SearchRecord      (tsp00_KeyPtr      pKey,
		                                      tsp00_Int4        KeyLen,
										      tsp00_Int4       &RecIndex,
										      tbd_searchresult &SearchResult) const;
	bool              bd600SpaceIsAvailable  (tsp00_Int4 RequiredLen) const;
	tsp00_Int4        bd600SumKeyLen         () const;
	tgg00_BasisError &bd600TrError           ();
	tgg00_BasisError  bd600TrError           () const;
	void              bd600UpdRecordSpace    (tsp00_Int4   RecSizeDelta,
										      tsp00_Int4   RecIndex,
									          tgg00_RecPtr pRec);

    tsp00_Int4          bd600RecOffset       (tsp00_Int4 RecIndex) const;
    tgg00_RecPtr        bd600FirstRecPtr     () const;

	static tgg00_RecPtr bd600FirstRecPtr     (tbd_nodeptr pNode);
	
#   if COMPILEMODE_MEO00 >= SLOW_MEO00 
    void              bd600Print             () const;
    void              bd600PrintPointerList  () const;
#   endif
	
	/* ---- protected members of class cbd600Node ----*/

   tbd_node_ptrs      bd600GetNodePtrs()
   {
	   return m_NodePtrs; //schmutz
   }
	
protected:
	/* Variables */
	tgg00_BasisError       &m_TrError;       /* For a convenient access                   */
	tbd_nodeptr            &m_pNode;         /* For a convenient access                   */
	cbd300_InvCurrentBasis &m_Current;       /* Transactions context, necessary for       */
	                                         /* DataCache operations and errorhandling    */
    tbd_node_ptrs           m_NodePtrs;      /* DataCache: Anchor to the page and the     */
	                                         /*            Caches Control Block           */
	tbd_node_request        m_RequestKind;   /* DataCache: for_update = locked exclusive  */
	                                         /*            for_read   = locked shared     */
	tbd00_PageLockMode      m_PageLockMode;  /* DataCache: tbd00_PageLockMode::fromConst(plmLock_ebd00) means the DC     */
	                                         /*            controls the concurrent        */
											 /*            page access                    */
	tsp00_Int4             *m_pRecIndexList; /* The OffsetList for the Records            */

	/* Methods */
	void             bd600_GetPageFromDataCache    (tsp00_PageNo            PageNo,
		                                            const tbd_node_request &RequestKind);
    void             bd600_CheckLeafCount          () const;
    void             bd600_GetIndexNodeStatistic   (tgg00_SampleInfo  &SampleInfo,
		                                            tbd_stat_aux_vars &StatAuxVars) const;
	void             bd600_GetInvLeafStatistic     (tgg00_SampleInfo  &SampleInfo) const;
	void             bd600_GetInvLeafSelectivity   (tgg00_SampleInfo  &SampleInfo) const;
	void             bd600_GetSubTreeLeafStatistic (tgg00_SampleInfo  &SampleInfo) const;
    void             bd600_GetSubTreeStatistics    (tgg00_RecPtr       pRec,
									                tgg00_SampleInfo  &SampleInfo) const;
	void			 bd610_Merge                   (cbd600_Node &SourceNode,
								                    tsp00_Int4  Offset);
	void			 bd610_AddPosition             (tsp00_Int4 RecPos, 
									                tsp00_Int4 RecIndex);
	void			 bd610_DelPosition             (tsp00_Int4 RecIndex);
	void			 bd610_SortForDistribution     (tsp00_Int4 LastDistribIndex);
	void			 bd610_UpdatePositions         (tsp00_Int4 TargetPos,
										            tsp00_Int4 ShiftLen);
	void			 bd610_UpdatePositionsRange    (tsp00_Int4 FirstIndex,
												    tsp00_Int4 LastIndex,
											 	    tsp00_Int4 MinRecOffset,
											        tsp00_Int4 MaxRecOffset,
												    tsp00_Int4 ShiftLen);
	void			 bd610_QuickSort               (tsp00_Int4      NumRecPosElem,
									                tgg00_PagePos  *pMinRecPosElem);
	void             bd610_CopyPointerList         (const cbd600_Node &SrcNode);
	void             bd610_DelHighIndexPositions   (tsp00_Int4 NumDeletedRecords);

    tsp00_Int4       bd620_CalcBlockLenAndSetIndexToNextBlock (cbd600_Node &AuxNode,
										                       tsp00_Int4  &CurrIndex, 
										                       tsp00_Int4   MaxIndex);
 	void			 bd620_DeleteRecordsFromPage     (bool       bRightDistribution,
												      tsp00_Int4 RecIndex);
	void			 bd620_FindOptimDistribForDelete (cbd600_Node &Neighbor,
													  bool         bRightDistribution,
													  tsp00_Int4   Covering,
													  tsp00_Int4   NeighborCovering,
													  bool        &bDistributionFound,
													  tsp00_Int4  &OptimRecIndex);
	void			 bd620_FindOptimDistribForInsert (bool              bRightDistribution,
													  tsp00_Int4        RequiredLen,
													  tsp00_Int4        NeighborCovering,
													  tsp00_Int4        RecIndex,
													  bool             &bDistributionFound,
													  tsp00_Int4       &OptimRecIndex,
													  bool             &bMoveNewRecordIntoNeighbor);
	void			 bd620_FindOptimDistribForUpdate (bool              bRightDistribution,
													  tsp00_Int4        RequiredLen,
													  tsp00_Int4        NeighborCovering,
													  tsp00_Int4        RecIndex,
													  bool             &bDistributionFound,
													  tsp00_Int4       &OptimRecIndex,
    												  bool             &bMoveRecordIntoNeighbor);
	void             bd620_MergeNodes                (cbd600_Node &LeftNode);
};
/*! endclass: cbd600_Node */

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

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

inline void
cbd600_Node::bd600CopyBody (cbd600_Node &SrcNode)
{
	ROUTINE_DBG_MEO00 ("bd600CopyBody");

	g10mv( __FILE__, 1,    
		sizeof (*SrcNode.m_pNode), sizeof(*m_pNode),
		SrcNode.m_pNode, BODY_BEG_BD00, 
		m_pNode,         BODY_BEG_BD00,
		SrcNode.m_pNode->nd_bottom() - BODY_BEG_BD00, m_TrError);
	if ( e_ok != m_TrError ) return;

    tsp00_Int4 PointerListSize = SrcNode.m_pNode->nd_record_cnt() * POINTERSIZE_BD00;

    g10mv( __FILE__,   1,
		sizeof (*SrcNode.m_pNode), sizeof(*m_pNode),
		SrcNode.m_pNode, MAX_BOTTOM_BD00 - PointerListSize, 
		m_pNode,         MAX_BOTTOM_BD00 - PointerListSize,
		PointerListSize, m_TrError);
	if ( e_ok != m_TrError ) return;

	m_pNode->nd_bottom()        = SrcNode.m_pNode->nd_bottom();
	m_pNode->nd_record_cnt()    = SrcNode.m_pNode->nd_record_cnt();
    m_pNode->ndLeafCount_bd00() = SrcNode.m_pNode->ndLeafCount_bd00(); //PTS 1103857 AK 02-09-1999

#   if COMPILEMODE_MEO00 >= SLOW_MEO00 
	t01p2int4 (bd_inv, "CopyNodeBody", SrcNode.m_pNode->nd_id(),
		               "to Node  #> ", m_pNode->nd_id());
#   endif
}

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

inline void
cbd600_Node::bd600CountRecords (tsp00_KeyPtr  pStartKey, 
								tsp00_Int4    StartKeyLen, 
								tsp00_KeyPtr  pStopKey,
								tsp00_Int4    StopKeyLen,
								tsp00_Int4   &RecordCnt) const
{
	ROUTINE_DBG_MEO00 ("bd600CountRecords");
	
	tsp00_Int4       StartRecIndex;
	tbd_searchresult KeySearchResult;
	
	bd600SearchRecord (pStartKey, StartKeyLen, StartRecIndex, KeySearchResult);
	if (lastfound == KeySearchResult || nonefound == KeySearchResult)
		RecordCnt = 0;
	else
	{
		tsp00_Int4       StopRecIndex;
		
		bd600SearchRecord (pStopKey, StopKeyLen, StopRecIndex, KeySearchResult);
		if (nextfound != KeySearchResult)
			RecordCnt = StopRecIndex - StartRecIndex + 1;
		else
			RecordCnt = StopRecIndex - StartRecIndex;
	}			
}

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

inline tsp00_Int4
cbd600_Node::bd600RecOffset (tsp00_Int4 RecIndex) const
{
	return *(m_pRecIndexList-RecIndex) - POS_OFF_DIFF_BD00;
}

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

inline tgg00_RecPtr
cbd600_Node::bd600RecPtr (tsp00_Int4 RecIndex) const
{
	return REINTERPRET_CAST(tgg00_RecPtr,REINTERPRET_CAST(tsp00_BytePtr,m_pNode)+bd600RecOffset(RecIndex));
}

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

inline tgg00_RecPtr
cbd600_Node::bd600FirstRecPtr (tbd_nodeptr pNode)
{
	return REINTERPRET_CAST(tgg00_RecPtr,REINTERPRET_CAST(tsp00_BytePtr,pNode)+pNode->nd_pointer_list() [MAX_POINTERINDEX_BD00 - POS_OFF_DIFF_BD00] - POS_OFF_DIFF_BD00);
}

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

inline tgg00_RecPtr
cbd600_Node::bd600FirstRecPtr() const
{
     return bd600FirstRecPtr( m_pNode );
}

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

inline bool
cbd600_Node::bd600IsAccessable () const
{
	return NULL != m_NodePtrs.np_ptr();
}

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

inline void
cbd600_Node::bd600_GetPageFromDataCache (tsp00_PageNo            PageNo,
						                 const tbd_node_request &RequestKind)
{
    ROUTINE_DBG_MEO00 ("bd600_GetPageFromDataCache");

	m_RequestKind = RequestKind;

	if ( bd600IsAccessable() )
        g01abort (csp3_bd_msg, csp3_n_btree, "bd600_GetPage:np_ptr!=NIL",
				  m_pNode->nd_id());

	bd13GetNode (m_Current, PageNo, m_PageLockMode, m_RequestKind, m_NodePtrs);
	if (e_ok != m_TrError) return;

	m_pRecIndexList = &m_pNode->nd_pointer_list() [MAX_POINTERINDEX_BD00 - POS_OFF_DIFF_BD00];
}

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

inline void
cbd600_Node::bd600GetNode (tsp00_PageNo            PageNo,
					       const tbd_node_request &RequestKind)
{
    ROUTINE_DBG_MEO00 ("bd600GetNode");

	bd600_GetPageFromDataCache (PageNo, RequestKind);
}

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

inline void
cbd600_Node::bd600New (tsp00_Int4 Level)
{
    ROUTINE_DBG_MEO00 ("bd600New");

	if (NULL != m_pNode)
        g01abort (csp3_bd_msg, csp3_n_btree,
		          "GBD600: New not allowed  ",
				  m_pNode->nd_id());

	b13new_node (Level, m_NodePtrs, m_Current);
	if (e_ok != m_TrError) return;
	m_pRecIndexList = &m_pNode->nd_pointer_list() [MAX_POINTERINDEX_BD00 - POS_OFF_DIFF_BD00];
	if ( LEAF_LEVEL_BD00 == Level ) m_pNode->ndLeafCount_bd00() = 1;
}

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

inline tgg00_RecPtr
cbd600_Node::bd600NewRecPtr()
{
    ROUTINE_DBG_MEO00 ("bd600NewRecPtr");
	/* this contructs a pointer to a new record on the node m_pNode */	
	return tgg00_RecPtr (tsp00_BytePtr(m_pNode) + m_pNode->nd_bottom() - POS_OFF_DIFF_BD00);
}

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

inline tsp00_Int4
cbd600_Node::bd600Covering () const
{
    ROUTINE_DBG_MEO00 ("bd600Covering");

	return m_NodePtrs.np_ptr()->nd_bottom() - BODY_BEG_BD00 +
		   (m_NodePtrs.np_ptr()->nd_record_cnt() << DIVISOR_POINTERSIZE_BD00);
}


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

inline void
cbd600_Node::bd600Exchange (cbd600_Node &Neighbor)
{
	ROUTINE_DBG_MEO00 ("bd600Exchange");

#   if COMPILEMODE_MEO00 >= SLOW_MEO00 
	t01p2int4 (bd_inv, "Exchange:   ", (NULL!=m_pNode)?(m_pNode->nd_id()):(-1),
		               "with Node:  ", (NULL!=Neighbor.m_pNode)?(Neighbor.m_pNode->nd_id()):(-1));
#   endif

    tbd_node_ptrs  AuxNodePtrs      = m_NodePtrs;
	tsp00_Int4    *pAuxRecIndexList = m_pRecIndexList;

    m_NodePtrs               = Neighbor.m_NodePtrs;
	m_pRecIndexList          = Neighbor.m_pRecIndexList;

    Neighbor.m_NodePtrs      = AuxNodePtrs;
	Neighbor.m_pRecIndexList = pAuxRecIndexList;
}

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

inline void
cbd600_Node::bd600GetNode (tsp00_PageNo PageNo)
{
	bd600_GetPageFromDataCache (PageNo, m_RequestKind);
}

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

inline bool
cbd600_Node::bd600IsLeaf() const
{
	return LEAF_LEVEL_BD00 == m_NodePtrs.np_ptr()->nd_level();
}

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

inline bool
cbd600_Node::bd600IsUpdateable () const
{
	return nr_for_update == m_RequestKind;
}

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

inline bool
cbd600_Node::bd600IsRoot() const
{
	return m_NodePtrs.np_ptr()->nd_id()== m_NodePtrs.np_ptr()->nd_root();
}

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

inline tsp00_Int4
cbd600_Node::bd600Level() const
{
	return m_NodePtrs.np_ptr()->nd_level();
}

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

inline tsp00_PageNo
cbd600_Node::bd600RightNeighbor() const
{
	return m_NodePtrs.np_ptr()->nd_right();
}


#if COMPILEMODE_MEO00 >= SLOW_MEO00 

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

inline void 
cbd600_Node::bd600PrintPointerList () const
{
	for (tsp00_Int4 CurrRecIndex = FIRST_REC_INDEX_BD00;
	     CurrRecIndex < m_pNode->nd_record_cnt();
		 CurrRecIndex++)
	{
		t01p4int4 (bd_oflw, "RecIndex(0) ",
			CurrRecIndex,
			*(m_pRecIndexList-CurrRecIndex),
            bd600RecPtr(CurrRecIndex)->recLen_gg00(),
            bd600RecPtr(CurrRecIndex)->recKeyLen_gg00());
	}
}

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

inline void 
cbd600_Node::bd600Print () const
{
	t01int4   (bd_inv, "NodeId      ", m_pNode->nd_id());
	t01p2int4 (bd_inv, "RecordCnt   ", m_pNode->nd_record_cnt(),
		               "Bottom      ", m_pNode->nd_bottom());
	t01addr   (bd_inv, "NodeAddr    ", m_pNode);
	bd600PrintPointerList ();
	t01sname  (bd_oflw, "Body        ");
	t01page   (bd_oflw, *m_NodePtrs.np_ptr_buf(), POS_OFF_DIFF_BD00, m_pNode->nd_bottom());
}


#endif

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

inline tsp00_PageNo
cbd600_Node::bd600GetId () const
{
	return m_NodePtrs.np_ptr()->nd_id();
}

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

inline tsp00_Int4
cbd600_Node::bd600PageConverterVersion () const
{
	return m_NodePtrs.np_ptr()->nd_conv_version();
}

/*---------------------------------------------------------------------------*/
inline void
cbd600_Node::bd600Free ()
{
    ROUTINE_DBG_MEO00 ("bd600Free");

    if ( NULL == m_NodePtrs.np_ptr() ) return;

	const tsp00_PageNo FreePno = bd600GetId();

	if ( FreePno == m_NodePtrs.np_ptr()->nd_root() )
	{
		m_Current.bd300FreeRoot ();

		m_NodePtrs.np_ptr()   = NULL;
		m_NodePtrs.np_cbptr() = NULL;
	}
	else
	{
        const SAPDB_Int4 freePageVersion = bd600PageConverterVersion();

		bd600Release (nr_for_update == m_RequestKind);
		bd13FreePageNo (FreePno, freePageVersion, m_Current);
	}
}


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

inline tbd_nodeptr
cbd600_Node::bd600GetNodePtr ()
{
	return m_NodePtrs.np_ptr();
}

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

inline tsp00_Int4 &
cbd600_Node::bd600LeafCount()
{
	return m_NodePtrs.np_ptr()->ndLeafCount_bd00();
}

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

inline tsp00_Int4
cbd600_Node::bd600NumRecords () const
{
	return m_pNode->nd_record_cnt();
}

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

inline bool
cbd600_Node::bd600SpaceIsAvailable (tsp00_Int4 RequiredLen) const
{
    ROUTINE_DBG_MEO00 ("bd600SpaceIsAvailable");
    
    // In case of an insert RequiredLen contains the recordlength as well
    // as the bytes for the pointerlist entry
    
    return RequiredLen + m_pNode->nd_bottom() <= MAX_BOTTOM_BD00 - 
        (m_pNode->nd_record_cnt() << DIVISOR_POINTERSIZE_BD00);
}

/*---------------------------------------------------------------------------*/
inline tsp00_Int4
cbd600_Node::bd600SumKeyLen () const
{
	tsp00_Int4 ResultLen = 0;
	for (tsp00_Int4 RecIndex = FIRST_REC_INDEX_BD00;
	     RecIndex < m_pNode->nd_record_cnt();
		 RecIndex ++)
	{
		ResultLen += bd600RecPtr (RecIndex)->recKeyLen_gg00();
	}
	return ResultLen;
}

/*---------------------------------------------------------------------------*/
inline tgg00_BasisError
cbd600_Node::bd600TrError() const
{
	return m_TrError;
}

/*---------------------------------------------------------------------------*/
inline tgg00_BasisError &
cbd600_Node::bd600TrError()
{
	return m_TrError;
}

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

inline tsp00_Int4   	
cbd600_Node::bd600MaxRecIndex() const
{
  return m_pNode->nd_record_cnt() - 1;
}

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

inline void 
cbd600_Node::bd600Move (tsp00_PageNo NewId)
{
	ROUTINE_DBG_MEO00 ("bd600Move");

	if ( bd600IsAccessable() )
    {
        if ( NewId == bd600GetId() )
            return;
        
        bd600Release(nr_for_update == m_RequestKind);
    }

	bd13GetNode (m_Current, NewId, m_PageLockMode, m_RequestKind, m_NodePtrs);
	if (e_ok != m_TrError) return;

	m_pRecIndexList = &m_pNode->nd_pointer_list() [MAX_POINTERINDEX_BD00 - POS_OFF_DIFF_BD00];
}

/*---------------------------------------------------------------------------*/
 
inline void
cbd600_Node::bd600EvalSepKeyLen (tsp00_KeyPtr pKey,
							     tsp00_Int4   KeyLen,
							     tsp00_KeyPtr pNewSepKey,
							     tsp00_Int2   &NewSepKeyLen) const
{
	ROUTINE_DBG_MEO00 ("bd600EvalSepKeyLen");

	tsp00_Int4 ByteOffset;
	tsp00_Int4 MinSepKeyLen;

	/* predsep < sep */
	if ( KeyLen <= NewSepKeyLen )
		MinSepKeyLen = KeyLen;
	else
		MinSepKeyLen = NewSepKeyLen;

	for ( ByteOffset=0;
	      (*(pKey+ByteOffset) == *(pNewSepKey+ByteOffset)) &&
		  (ByteOffset < MinSepKeyLen);
		  ++ByteOffset)
		/*empty*/;

	if ( ByteOffset < MinSepKeyLen )
	{
		if ( *(pKey+ByteOffset) > *(pNewSepKey+ByteOffset) )
		{
			g01opmsg (sp3p_console, sp3m_error,
				  BD600_X1_INVALID_SEPARATOR_SP03, csp3_n_btree,
				  "BD600: predsep.k > sep.k", 0);
			m_TrError = e_invalid_leaves_structure;
			return;
		}
	}
	else
	{
		if ( MinSepKeyLen == NewSepKeyLen )
		{
			g01opmsg (sp3p_console, sp3m_error,
				  BD600_X2_INVALID_SEPARATOR_SP03, csp3_n_btree,
				  "BD600: min_len = sep.len", 0);
			m_TrError = e_invalid_leaves_structure;
			return;
		}
	}

	/* include the next nonzero byte: */
	if ( ByteOffset < sizeof (tsp00_Key) )
	{
		for ( /*empty*/;
		      (0 == *(pNewSepKey+ByteOffset)) && (ByteOffset < NewSepKeyLen);
			  ++ByteOffset)
			/*empty*/ ;
		NewSepKeyLen = ByteOffset+1;
	}
}
 

/*---------------------------------------------------------------------------*/
 
inline void
cbd600_Node::bd600BuildSeparatorKey (bool          bNodeIsLeft,
								     tsp00_KeyPtr  pNeighborKey,
                                     tsp00_Int4    NeighborKeyLen,
                                     tsp00_KeyPtr &pNewSepKey,
                                     tsp00_Int2   &NewSepKeyLen) const
{
	ROUTINE_DBG_MEO00 ("bd600BuildSeparatorKey1");

	tgg00_RecPtr pRec;

	if ( bNodeIsLeft )
	{
		pRec = bd600RecPtr (bd600MaxRecIndex());
		pNewSepKey   = pNeighborKey;
		NewSepKeyLen = NeighborKeyLen;
		if ( LEAF_LEVEL_BD00 == m_pNode->nd_level() )
			bd600EvalSepKeyLen (tsp00_BytePtr(pRec)+cgg_rec_key_offset, pRec->recKeyLen_gg00(),
				pNewSepKey, NewSepKeyLen);
	}
	else
	{
		pRec = bd600RecPtr (FIRST_REC_INDEX_BD00);
		pNewSepKey   = tsp00_BytePtr(pRec)+cgg_rec_key_offset;
		NewSepKeyLen = pRec->recKeyLen_gg00();
		if ( LEAF_LEVEL_BD00 == m_pNode->nd_level() )
			bd600EvalSepKeyLen (pNeighborKey, NeighborKeyLen, pNewSepKey, NewSepKeyLen);
	}

#   if COMPILEMODE_MEO00 >= SLOW_MEO00
	t01moveobj (bd_index, pRec, cgg_rec_key_offset+POS_OFF_DIFF_BD00, pRec->recKeyLen_gg00());
	t01moveobj (bd_index, pNewSepKey, POS_OFF_DIFF_BD00, NewSepKeyLen);
#   endif

	if ( e_invalid_leaves_structure == m_TrError )
		bd600Dump (csp3_bd_msg, "bd600BuildNewSeparator: ");
}

/*---------------------------------------------------------------------------*/
 
inline void
cbd600_Node::bd600BuildSeparatorKey (cbd600_Node  &RightNeighbor,
								     tsp00_KeyPtr &pSepKey,
								     tsp00_Int2   &SepKeyLen) const
{
	ROUTINE_DBG_MEO00 ("bd600BuildSeparatorKey2");

	tgg00_RecPtr pRec = RightNeighbor.bd600RecPtr (FIRST_REC_INDEX_BD00);

	pSepKey   = REINTERPRET_CAST(tsp00_BytePtr,pRec) + cgg_rec_key_offset;
	SepKeyLen = pRec->recKeyLen_gg00();

	pRec      = bd600RecPtr (bd600MaxRecIndex());
	
#   if COMPILEMODE_MEO00 >= SLOW_MEO00
	t01moveobj (bd_index, pRec, cgg_rec_key_offset+POS_OFF_DIFF_BD00, pRec->recKeyLen_gg00());
	t01moveobj (bd_index, pSepKey, POS_OFF_DIFF_BD00, SepKeyLen);
#   endif

	if ( LEAF_LEVEL_BD00 == m_pNode->nd_level() )
		bd600EvalSepKeyLen (tsp00_BytePtr(pRec)+cgg_rec_key_offset, pRec->recKeyLen_gg00(),
			pSepKey, SepKeyLen);

	if ( e_invalid_leaves_structure == m_TrError )
	{
		bd600Dump (csp3_bd_msg, "bd600BuildSeparator: lef");
		RightNeighbor.bd600Dump (csp3_bd_msg, "bd600BuildSeparator: rig");
	}
#   if COMPILEMODE_MEO00 >= SLOW_MEO00
	t01moveobj (bd_index, pSepKey, POS_OFF_DIFF_BD00, SepKeyLen);
#   endif
}
 
/*---------------------------------------------------------------------------*/

inline
cbd600_Node::cbd600_Node (const cbd600_Node &Node)
: m_TrError       (Node.m_TrError),
  m_Current       (Node.m_Current),
  m_RequestKind   (Node.m_RequestKind),
  m_PageLockMode  (Node.m_PageLockMode),
  m_pRecIndexList (Node.m_pRecIndexList),
  m_pNode (m_NodePtrs.np_ptr())
{
  if (e_ok != m_TrError) return; // PTS 1104721 TS 1999-11-23

  bd13GetNode (m_Current, Node.bd600GetId(), m_PageLockMode, m_RequestKind, m_NodePtrs);
}

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

inline
cbd600_Node::cbd600_Node (cbd300_InvCurrentBasis   &Current,
		                  const tbd00_PageLockMode &PageLockMode)
: m_TrError       (Current.curr_trans->trError_gg00),
  m_pNode         (m_NodePtrs.np_ptr()),
  m_Current       (Current),
  m_RequestKind   (Current.bd300RootRequestKind()),
  m_PageLockMode  (PageLockMode),
  m_pRecIndexList (NULL)
{
    ROUTINE_DBG_MEO00 ("cbd600_Node_Root");

    if (e_ok != m_TrError) return; // PTS 1104721 TS 1999-11-23

    m_NodePtrs.np_ptr()   = NULL;
    m_NodePtrs.np_cbptr() = NULL;
	bd600GetNode (m_Current.curr_tree_id.fileRoot_gg00());
}

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

inline
cbd600_Node::cbd600_Node (cbd300_InvCurrentBasis   &Current,
						  const tbd_node_request   &RequestKind,
						  const tbd00_PageLockMode &PageLockMode)
: m_TrError       (Current.curr_trans->trError_gg00),
  m_pNode         (m_NodePtrs.np_ptr()),
  m_Current       (Current),
  m_RequestKind   (RequestKind),
  m_PageLockMode  (PageLockMode),
  m_pRecIndexList (NULL)
{
    ROUTINE_DBG_MEO00 ("cbd600_Node");

    m_NodePtrs.np_ptr()   = NULL;
    m_NodePtrs.np_cbptr() = NULL;
}

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

inline
cbd600_Node::cbd600_Node (cbd300_InvCurrentBasis   &Current,
						  const tbd_node_request   &RequestKind,
						  tsp00_PageNo              Pno,
						  const tbd00_PageLockMode &PageLockMode)
: m_TrError       (Current.curr_trans->trError_gg00),
  m_pNode         (m_NodePtrs.np_ptr()),
  m_Current       (Current),
  m_RequestKind   (RequestKind),
  m_PageLockMode  (PageLockMode),
  m_pRecIndexList (NULL)
{
    ROUTINE_DBG_MEO00 ("cbd600_Node_Pno");

   if (e_ok != m_TrError) return; // PTS 1104721 TS 1999-11-23

    m_NodePtrs.np_ptr()   = NULL;
    m_NodePtrs.np_cbptr() = NULL;
	bd600GetNode (Pno);
}

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

inline
cbd600_Node::cbd600_Node (cbd300_InvCurrentBasis   &Current,
						  const tbd_node_request   &RequestKind,
						  tbd_node_ptrs            &Nptr,
 						  const tbd00_PageLockMode &PageLockMode)
: m_TrError       (Current.curr_trans->trError_gg00),
  m_pNode         (m_NodePtrs.np_ptr()),
  m_Current       (Current),
  m_NodePtrs      (Nptr),
  m_RequestKind   (RequestKind),
  m_PageLockMode  (PageLockMode),
  m_pRecIndexList (&m_pNode->nd_pointer_list() [MAX_POINTERINDEX_BD00 - POS_OFF_DIFF_BD00])
{
    ROUTINE_DBG_MEO00 ("cbd600_Node_PascalInterface");
}


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

inline
cbd600_Node::cbd600_Node (cbd300_InvCurrentBasis   &Current,
						  tbd_node                 &Buffer,
						  const tbd00_PageLockMode &PageLockMode)
: m_TrError       (Current.curr_trans->trError_gg00),
  m_pNode         (m_NodePtrs.np_ptr()),
  m_Current       (Current),
  m_RequestKind   (tbd_node_request::fromConst(nr_for_update)),
  m_PageLockMode  (PageLockMode),
  m_pRecIndexList (&Buffer.nd_pointer_list() [MAX_POINTERINDEX_BD00 - POS_OFF_DIFF_BD00])
{
    ROUTINE_DBG_MEO00 ("cbd600_Node_Buffer");

    if (e_ok != m_TrError) return; // PTS 1104721 TS 1999-11-23

    m_NodePtrs.np_ptr()   = &Buffer;
    m_NodePtrs.np_cbptr() = NULL;
}


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

inline cbd600_Node::~cbd600_Node ()
{
    ROUTINE_DBG_MEO00 ("cbd600_~Node");

#	if COMPILEMODE_MEO00 >= SLOW_MEO00 
    t01int4 (bd_inv, "Node:       ", (m_pNode != NULL)?(m_pNode->nd_id()):(NIL_PAGE_NO_GG00));
#	endif

	bd600Release (nr_for_update == m_RequestKind);

	if ( e_page_in_wrong_tree == m_TrError)
    {
        bd600Dump (csp3_bd_msg, "~cbd600_Node: PageInWron");
    }

#	if COMPILEMODE_MEO00 >= SLOW_MEO00 
	if ( e_ok != m_TrError)
		t01basis_error (bd_inv, "TrError     ", m_TrError);
#	endif
}

#endif  /* GBD600_H */
