/**********************************************************
/************** DIR STRUCTURES and CONSTANTS **************
/**********************************************************
/**/

#include "node.h"

/************** DIR API defines and types ******************
/***********************************************************
/**/
typedef struct {
	ULONG		ulLT;
	ULONG		ulTotal;
	} FRAC;

typedef INT POS;
#define posFirst	  			0
#define posLast					1
#define posDown					2
#define posFrac					3

#define fDIRNull	   			0
#define fDIRPurgeParent			(1<<0)
#define fDIRBackToFather		(1<<1)
#define fDIRNeighborKey			(1<<2)
#define fDIRPotentialNode 		(1<<3) 
#define fDIRAllNode				(1<<4)
#define fDIRAllPage				(1<<5)
#define fDIRReplace				(1<<6)
#define fDIRReplaceDuplicate	(1<<7)
#define fDIRDuplicate 			(1<<8)
#define fDIRSpace	   			(1<<9)
#define fDIRVersion				(1<<10)
#define fDIRAppendItem			(1<<12)
#define	fDIRDeleteItem			(1<<13)
#define fDIRLogColumnDiffs		(1<<14)
#define fDIRLogChunkDiffs		(1<<15)
#define fDIRNoLog				(1<<16)
#define fDIRNoVersion			0
#define fDIRNoMPLRegister		(1<<17)

/*	item list nodes not versioned
/**/
#define fDIRItemList		   	fDIRPotentialNode

struct _dib {
	POS		pos;
	KEY		*pkey;
	INT		fFlags;
	};

#define	itagOWNEXT		1
#define	itagAVAILEXT 	2
#define	itagDATA		3
#define	itagLONG		4
#define itagAUTOINC		5

#define PgnoFDPOfPfucb(pfucb) ((pfucb)->u.pfcb->pgnoFDP)
#define PgnoRootOfPfucb(pfucb) ((pfucb)->u.pfcb->pgnoFDP)
#define ItagRootOfPfucb(pfucb) itagDATA

#define	ErrDIRGetBookmark( pfucb, psrid )								\
	( PcsrCurrent( pfucb )->csrstat == csrstatOnCurNode ||				\
		PcsrCurrent( pfucb )->csrstat == csrstatDeferGotoBookmark ?		\
		( *psrid = PcsrCurrent( pfucb )->bm, JET_errSuccess ) :			\
		ErrERRCheck( JET_errNoCurrentRecord ) )

#define	DIRGetBookmark( pfucb, psrid )									\
	( *((SRID *)psrid) = PcsrCurrent( pfucb )->bm )

#define DIRGotoBookmark	DIRDeferGotoBookmark

#ifdef PREREAD

#define DIRDeferGotoBookmark( pfucb, bmT )								\
	{																	\
	FUCBResetPreread( pfucb );											\
	PcsrCurrent( pfucb )->csrstat = csrstatDeferGotoBookmark;			\
	PcsrCurrent( pfucb )->bm = bmT;										\
	( pfucb )->sridFather = sridNull;									\
	DIRSetRefresh( pfucb );														\
	}																					

#else

#define DIRDeferGotoBookmark( pfucb, bmT )								\
	{																	\
	PcsrCurrent( pfucb )->csrstat = csrstatDeferGotoBookmark;			\
	PcsrCurrent( pfucb )->bm = bmT;										\
	( pfucb )->sridFather = sridNull;									\
	DIRSetRefresh( pfucb );														\
	}	

#endif	// PREREAD

#define DIRGotoBookmarkItem( pfucb, bmT, itemT )  						\
	{																	\
	PcsrCurrent( pfucb )->csrstat = csrstatDeferGotoBookmark;			\
	PcsrCurrent( pfucb )->bm = bmT;						  				\
	PcsrCurrent( pfucb )->item = itemT;				  					\
	( pfucb )->sridFather = sridNull;									\
	DIRSetRefresh( pfucb );												\
	}																					

#define DIRGotoPgnoItag( pfucb, pgnoT, itagT )   						\
	{																	\
	PcsrCurrent( pfucb )->csrstat = csrstatOnCurNode;					\
	PcsrCurrent( pfucb )->bm = SridOfPgnoItag( (pgnoT), (itagT) );		\
	PcsrCurrent( pfucb )->pgno = (pgnoT);	 							\
	PcsrCurrent( pfucb )->itag = (itagT);	 							\
	( pfucb )->sridFather = sridNull;									\
	DIRSetRefresh( pfucb );														\
	}

#define DIRGotoFDPRoot( pfucb )									  		\
	{															  	 	\
	PcsrCurrent( pfucb )->csrstat = csrstatOnFDPNode;					\
	PcsrCurrent( pfucb )->bm =									  		\
		SridOfPgnoItag( PgnoFDPOfPfucb( pfucb ), itagFOP );				\
	PcsrCurrent( pfucb )->pgno = PgnoFDPOfPfucb( pfucb ); 				\
	PcsrCurrent( pfucb )->itag = itagFOP;								\
	PcsrCurrent( pfucb )->itagFather = itagFOP;							\
	( pfucb )->sridFather = sridNull;									\
	if ( !FBFReadAccessPage( pfucb, PcsrCurrent( pfucb )->pgno ) )		\
		{															   	\
		if ( ErrBFReadAccessPage( pfucb,							   	\
			PcsrCurrent( pfucb )->pgno ) < 0 )							\
			{														   	\
			DIRSetRefresh( pfucb );									   	\
			}															\
		else														   	\
			{														   	\
			NDGet( pfucb, PcsrCurrent( pfucb )->itag );					\
			DIRSetFresh( pfucb );										\
			}															\
		}																\
	}

#define DIRGotoOWNEXT( pfucb, pgnoT )									\
	{																	\
	DIRGotoPgnoItag( pfucb, pgnoT, itagOWNEXT );  						\
	Assert( ( pfucb )->sridFather == sridNull );						\
	PcsrCurrent( pfucb )->itagFather = itagFOP;							\
	}

#define DIRGotoAVAILEXT( pfucb, pgnoT )		 							\
	{																	\
	DIRGotoPgnoItag( pfucb, pgnoT, itagAVAILEXT );  					\
	PcsrCurrent( pfucb )->itagFather = itagFOP;							\
	}

#define DIRGotoLongRoot( pfucb )										\
	{																	\
	PcsrCurrent( pfucb )->csrstat = csrstatOnCurNode;					\
	PcsrCurrent( pfucb )->bm =											\
		SridOfPgnoItag( PgnoFDPOfPfucb( pfucb ), itagLONG );			\
	PcsrCurrent( pfucb )->pgno = PgnoFDPOfPfucb( pfucb ); 				\
	PcsrCurrent( pfucb )->itag = itagLONG;								\
	PcsrCurrent( pfucb )->itagFather = itagNull;						\
	( pfucb )->sridFather = sridNull;									\
	if ( !FBFReadAccessPage( pfucb, PcsrCurrent( pfucb )->pgno ) )		\
		{																\
		if ( ErrBFReadAccessPage( pfucb,								\
			PcsrCurrent( pfucb )->pgno ) < 0 )							\
			{															\
			DIRSetRefresh( pfucb );										\
			}															\
		else															\
			{															\
			NDGet( pfucb, PcsrCurrent( pfucb )->itag );					\
			DIRSetFresh( pfucb );										\
			}															\
		}																\
	}

#define DIRGotoDataRoot( pfucb )										\
	{																	\
	PcsrCurrent( pfucb )->csrstat = csrstatOnCurNode;					\
	PcsrCurrent( pfucb )->bm =											\
		SridOfPgnoItag( PgnoFDPOfPfucb( pfucb ), itagDATA );			\
	PcsrCurrent( pfucb )->pgno = PgnoFDPOfPfucb( pfucb ); 				\
	PcsrCurrent( pfucb )->itag = itagDATA;								\
	PcsrCurrent( pfucb )->itagFather = itagNull;						\
	( pfucb )->sridFather = sridNull;									\
	if ( !FBFReadAccessPage( pfucb, PcsrCurrent( pfucb )->pgno ) )		\
		{																\
		if ( ErrBFReadAccessPage( pfucb,								\
			PcsrCurrent( pfucb )->pgno ) < 0 )							\
			{															\
			DIRSetRefresh( pfucb );										\
			}															\
		else															\
			{															\
			NDGet( pfucb, PcsrCurrent( pfucb )->itag );					\
			DIRSetFresh( pfucb );										\
			}															\
		}																\
	}

#define FDIRDataRootRoot( pfucb, pcsr )								\
	(	(pcsr)->pgno == PgnoFDPOfPfucb( pfucb ) &&					\
		(pcsr)->itag == ItagRootOfPfucb( pfucb ) )

#define DIRDeferMoveFirst( pfucb )									\
	{																\
	PcsrCurrent( pfucb )->csrstat = csrstatDeferMoveFirst;			\
	DIRSetRefresh( pfucb );											\
	}

#define DIRSetIndexRange		FUCBSetIndexRange
#define DIRResetIndexRange		FUCBResetIndexRange

ERR ErrDIROpen( PIB *ppib, FCB *pfcb, DBID dbid, FUCB **ppfucb );
VOID DIRClose( FUCB *pfucb );
ERR ErrDIRDown( FUCB *pfucb, DIB *pdib );
ERR ErrDIRDownFromDATA( FUCB *pfucb, KEY *pkey );
VOID DIRUp( FUCB *pfucb, INT ccsr );
ERR ErrDIRNext( FUCB *pfucb, DIB *pdib );
ERR ErrDIRPrev( FUCB *pfucb, DIB *pdib );
ERR ErrDIRGet( FUCB *pfucb );
ERR ErrDIRCheckIndexRange( FUCB *pfucb );
ERR ErrDIRGetBMOfItemList( FUCB *pfucb, SRID *pbmItemList );

ERR ErrDIRGetWriteLock( FUCB *pfucb );

ERR ErrDIRInsert( FUCB *pfucb, LINE *pline, KEY *pkey, INT fFlags );
ERR ErrDIRInitAppendItem( FUCB *pfucb );
ERR ErrDIRAppendItem( FUCB *pfucb, LINE *pline, KEY *pkey, SRID sridPrev  );
ERR ErrDIRTermAppendItem( FUCB *pfucb );

ERR ErrDIRCreateDirectory( FUCB *pfucb, CPG cpgMin, PGNO *ppgnoFDP );
#define ErrDIRDeleteDirectory( pfucb, pgnoFDP )		ErrSPFreeFDP( pfucb, pgnoFDP )

ERR ErrDIRDelete( FUCB *pfucb, INT fFlags );
ERR ErrDIRReplace( FUCB *pfucb, LINE *pline, INT fFlags );
ERR ErrDIRReplaceKey( FUCB *pfucb, KEY *pkeyTo, INT fFlags );

ERR ErrDIRDownKeyBookmark( FUCB *pfucb, KEY *pkey, SRID srid );
ERR ErrDIRGetPosition( FUCB *pfucb, ULONG *pulLT, ULONG *pulTotal );
ERR ErrDIRGotoPosition( FUCB *pfucb, ULONG ulLT, ULONG ulTotal );
ERR ErrDIRIndexRecordCount( FUCB *pfucb, ULONG *pulCount, ULONG ulCountMost, BOOL fNext );
ERR ErrDIRComputeStats( FUCB *pfucb, INT *pcitem, INT *pckey, INT *pcpage );

ERR ErrDIRDelta( FUCB *pfucb, INT iDelta, INT fFlags );

ERR ErrDIRBeginTransaction( PIB *ppib );
ERR ErrDIRRefreshTransaction( PIB *ppib );
ERR ErrDIRCommitTransaction( PIB *ppib, JET_GRBIT grbit );
VOID DIRPurge( PIB *ppib );
ERR ErrDIRRollback( PIB *ppib );

#define DIRBeforeFirst( pfucb )		( PcsrCurrent(pfucb)->csrstat = csrstatBeforeFirst )
#define DIRAfterLast( pfucb )		( PcsrCurrent(pfucb)->csrstat = csrstatAfterLast )
#define FDIRMostRecent				FBTMostRecent
#define FDIRDelta					FVERDelta

ERR ErrDIRDump( FUCB *pfucb, INT cchIndent );


/**********************************************************
/******************* DIR Internal *************************
/**********************************************************
/**/
#define	itagFOP				0
#define	cbSonMax			256
#define	qwDBTimeNull		0xffffffffffffffff
#define itagDIRDVSplitL		1
#define itagDIRDVSplitR		2

/*	maximum node data size for nodes which ErrNDDelta can be used on.
/*	Specifically this minimally supports long value root nodes.
/**/
#define	cbMaxCounterNode	8

/*  Offset of data field to counter. for long field reference counter.
 **/
#define ibCounter			0

/*	non-clustered index cursors already have item stored.
/**/
#ifdef DEBUG

#define CheckCSR( pfucb )       Assert( fRecovering ||					\
	(PcsrCurrent(pfucb) == pcsrNil ||						  			\
	PcsrCurrent(pfucb)->pcsrPath == pcsrNil ||							\
	PcsrCurrent(pfucb)->pgno != PcsrCurrent(pfucb)->pcsrPath->pgno ||	\
	PcsrCurrent(pfucb)->itag != PcsrCurrent(pfucb)->pcsrPath->itag ) );

#define DIRSetFresh( pfucb )										   	\
	{																   	\
	Assert( PcsrCurrent( pfucb )->csrstat == csrstatOnCurNode ||		\
		PcsrCurrent( pfucb )->csrstat == csrstatBeforeCurNode ||	   	\
		PcsrCurrent( pfucb )->csrstat == csrstatAfterCurNode || 	   	\
		PcsrCurrent( pfucb )->csrstat == csrstatOnFDPNode );		   	\
	AssertNDGet( pfucb, PcsrCurrent( pfucb )->itag ); 				   	\
	PcsrCurrent( pfucb )->qwDBTime = QwSTDBTimePssib( &(pfucb)->ssib ); \
	}

#define DIRSetRefresh( pfucb )											\
	{																	\
	Assert( PcsrCurrent( pfucb )->csrstat == csrstatOnCurNode ||		\
		PcsrCurrent( pfucb )->csrstat == csrstatBeforeCurNode ||		\
		PcsrCurrent( pfucb )->csrstat == csrstatAfterCurNode || 		\
		PcsrCurrent( pfucb )->csrstat == csrstatOnFDPNode ||			\
		PcsrCurrent( pfucb )->csrstat == csrstatDeferGotoBookmark ||	\
		PcsrCurrent( pfucb )->csrstat == csrstatDeferMoveFirst ||		\
		PcsrCurrent( pfucb )->csrstat == csrstatOnDataRoot );			\
	PcsrCurrent( pfucb )->qwDBTime = qwDBTimeNull;						\
	}

#else

#define CheckCSR( pfucb )

#define DIRSetFresh( pfucb )		 									   	\
	{																	   	\
	PcsrCurrent( pfucb )->qwDBTime = QwSTDBTimePssib( &(pfucb)->ssib ); 	\
	}

#define DIRSetRefresh( pfucb )  										   	\
	{																	   	\
	PcsrCurrent( pfucb )->qwDBTime = qwDBTimeNull; 						   	\
	}

#endif


/**********************************************************
/********************* BTREE API **************************
/**********************************************************
/**/
#define sridMin         0
#define sridMax         0xffffffff

/*	must be on node, i.e. on current node, before node or after node.
/*	Node must be in line cache.
/**/
#define DIRISetBookmark( pfucb, pcsr )									   	\
	{																	   	\
	AssertFBFReadAccessPage( (pfucb), (pcsr)->pgno );						\
																			\
	if ( FNDBackLink( *( (pfucb)->ssib.line.pb ) ) )						\
		(pcsr)->bm = *(SRID UNALIGNED *)PbNDBackLink( (pfucb)->ssib.line.pb );		\
	else																	\
		(pcsr)->bm = SridOfPgnoItag( (pcsr)->pgno, (pcsr)->itag );			\
	}


BOOL FBTMostRecent( FUCB *pfucb );

#define ErrBTNext( pfucb, pdib ) \
	( ErrBTNextPrev( pfucb, PcsrCurrent(pfucb), fTrue, pdib, NULL ) )
#define ErrBTPrev( pfucb, pdib ) \
	( ErrBTNextPrev( pfucb, PcsrCurrent(pfucb), fFalse, pdib, NULL ) )
#define	BTUp( pfucb )	FUCBFreeCSR( pfucb )

ERR ErrBTGet( FUCB *pfucb, CSR *pcsr );
ERR ErrBTGetNode( FUCB *pfucb, CSR *pcsr );
#ifdef DEBUG
VOID AssertBTGetNode( FUCB *pfucb, CSR *pcsr );
#else
#define	AssertBTGetNode
#endif
ERR ErrBTSetNodeHeader( FUCB *pfucb, BYTE bHeader );
ERR ErrBTReplaceKey( FUCB *pfucb, KEY *pkey, INT fFlags );
ERR ErrBTDown( FUCB *pfucb, DIB *pdib );
ERR ErrBTDownFromDATA( FUCB *pfucb, KEY *pkey );
ERR ErrBTNextPrev( FUCB *pfucb, CSR *pcsr, INT fNext, DIB *pdib, BOOL *pfEmptyPage );
ERR ErrBTSeekForUpdate( FUCB *pfucb, KEY *pkey, PGNO pgno, INT itag, INT fDIRFlags );
ERR ErrBTInsert( FUCB *pfucb, INT fHeader, KEY *pkey, 
				 LINE *pline, INT fDIRFlags, BOOL *pfCleaned );
ERR ErrBTReplace( FUCB *pfucb, LINE *pline, 
				  INT fFlags, BOOL *pfCleaned );
ERR ErrBTDelete( FUCB *pfucb, INT fFlags );
ERR ErrBTMakeRoom( FUCB *pfucb, CSR *pcsrRoot, INT cbReq );
ERR ErrBTGetPosition( FUCB *pfucb, ULONG *pulLT, ULONG *pulTotal );
ERR ErrBTGotoBookmark( FUCB *pfucb, SRID srid );
ERR ErrBTGetInvisiblePagePtr( FUCB *pfucb, SRID sridFather );
#ifdef DEBUG
ERR ErrBTCheckInvisiblePagePtr( FUCB *pfucb, SRID sridFather );
#endif

#ifdef DEBUG
VOID BTCheckSplit( FUCB *pfucb, CSR *pcsr );
#else
#define BTCheckSplit( pfucb, pcsr )
#endif


/**********************************************************
/*********************** BT Split *************************
/**********************************************************
/**/
typedef enum {
	splittNull,
	splittVertical,
	splittDoubleVertical,
	splittLeft,
	splittRight,
	splittAppend
	} SPLITT;
	
typedef enum {
	opReplace,
	opInsert
	} OPERATION;

typedef struct {
	PN		pn;
	QWORD	qwDBTime;
} LFINFO;						/* leaf split info */


typedef struct
	{
	SRID	sridNew;
	SRID	sridBackLink;
	} BKLNK;


typedef struct _split {
	PIB			*ppib;
	PGNO		pgnoSplit;
	PGNO		pgnoNew;
	PGNO		pgnoNew2;
	PGNO		pgnoNew3;
	PGNO		pgnoSibling;
	
	BF			*pbfSplit;			/* BF of page being split */
	BF			*pbfNew;			/* BF of new page of this split */
	BF			*pbfNew2;			/* BF of new page of this split */
	BF			*pbfNew3;			/* BF of new page of this split */
	BF			*pbfSibling;		/* BF of sibling page of this H split */
	BF			*pbfPagePtr;

	BOOL		fNoRedoNew;			/* no need to redo new page */
	BOOL		fNoRedoNew2;		/* no need to redo new page 2 */
	BOOL		fNoRedoNew3;		/* no need to redo new page 3 */
	
	BF			**rgpbf;			/* BF of backlink page. */
	INT	  		cpbf;
	INT	  		cpbfMax;

	BKLNK		*rgbklnk;			/* SRID of backlinks. */
	INT	  		cbklnk;
	INT			cbklnkAlloc;
	INT	  		cbklnkMax;
	
	QWORD		qwDBTimeRedo;		/* redo timestamp */
	
	INT			itagSplit;
	INT			ibSon;
	KEY	  		key;
	KEY	  		keyMac;
	
	SPLITT  	splitt;
	BOOL		fLeaf;
	OPERATION	op;
	BOOL		fFDP;
	DBID		dbid;
	INT			itagNew;
	INT			itagPagePointer;
	
	BYTE		rgbSonSplit[cbSonMax];
	BYTE		rgbSonNew[cbSonMax];

	BYTE		rgbkeyMac[JET_cbKeyMost];
	BYTE		rgbKey[JET_cbKeyMost];

	/*	mapping from old to new tags for use in MCM
	/**/
	BYTE		mpitag[ctagMax];
	INT			ipcsrMac;				/* preallocated resource for csr */
#define ipcsrSplitMax 4
	CSR			*rgpcsr[ipcsrSplitMax];
} SPLIT;


typedef struct _rmpage {
	PIB			*ppib;
	
	QWORD		qwDBTimeRedo;			/* redo timestamp */
	
	BF			*pbfLeft;
	BF			*pbfRight;
	BF			*pbfFather;

	BKLNK		**rgbklnk;				/* latched buffers required for rmpage */
	INT			cbklnk;
	INT	  		cbklnkMax;

	BF			**rgpbf;				/* latched buffers required for rmpage */
	INT			cpbf;
	INT	  		cpbfMax;

	PGNO		pgnoRemoved;
	PGNO		pgnoLeft;
	PGNO		pgnoRight;
	PGNO		pgnoFather;
	INT			itagPgptr;
	INT			itagFather;
	INT			ibSon;
	DBID		dbid;
	} RMPAGE;
	
#define CbFreeDensity(pfucb) \
	( (pfucb)->u.pfcb != pfcbNil ? (INT)(pfucb)->u.pfcb->cbDensityFree : 0 )

/*	protypes for split used by recovery of split operations.
/**/
ERR ErrBTStoreBackLinkBuffer( SPLIT *psplit, BF *pbf, BOOL *pfAlreadyLatched );
ERR ErrBTSplit( FUCB *pfucb, INT cbNode, INT cbReq, KEY *pkey, INT fFlags );
ERR ErrBTSplitPage( FUCB *pfucb, CSR *pcsr,	CSR *pcsrRoot,
	KEY keySplit, INT cbNode, INT cbReq, BOOL fReplace, BOOL fAppendPage );
BOOL FBTSplit( SSIB *pssib, INT cbReq, INT citagReq );
BOOL FBTAppendPage( FUCB *pfucb, CSR *pcsr, INT cbReq, INT cbPageAdjust, INT cbFreeDensity, INT citagReq );
INT CbBTFree( FUCB *pfucb, INT cbFreeDensity );

#define fAllocBufOnly		fTrue
#define fDoMove				fFalse

ERR ErrBTSplitVMoveNodes(
	FUCB	*pfucb,
	FUCB	*pfucbNew,
	SPLIT	*psplit,
	CSR 	*pcsr,
	BYTE	*rgb,
	BOOL	fNoMove);
ERR ErrBTSplitDoubleVMoveNodes(
	FUCB	*pfucb,
	FUCB	*pfucbNew,
	FUCB	*pfucbNew2,
	FUCB	*pfucbNew3,
	SPLIT	*psplit,
	CSR		*pcsr,
	BYTE	*rgb,
	BOOL	fNoMove);
ERR ErrBTSplitHMoveNodes(
	FUCB	*pfucb,
	FUCB	*pfucbNew,
	SPLIT	*psplit,
	BYTE	*rgb,
	BOOL	fNoMove);
ERR ErrBTInsertPagePointer( FUCB *pfucb, CSR *pcsrPagePointer, SPLIT *psplit, BYTE *rgb );
ERR ErrBTCorrectLinks(
	SPLIT *psplit,
	FUCB *pfucb,
	SSIB *pssib,
	SSIB *pssibNew);
VOID BTReleaseSplitBfs ( BOOL fRedo, SPLIT *psplit, ERR err );
VOID BTReleaseRmpageBfs( BOOL fRedo, RMPAGE *prmpage );

ERR ErrBTMoveSons( SPLIT *psplit, 
	FUCB	*pfucb, 
	FUCB	*pfucbNew, 
	INT		itagSonTable,
	BYTE	*rgbSon, 
	BOOL	fVisibleSons, 
	BOOL	fNoMove,
	BKLNK	*pbklnk,
	INT		cbklnk );
	
ERR ErrBTSetUpSplitPages( FUCB *pfucb, FUCB *pfucbNew,
	FUCB *pfucbNew2, FUCB *pfucbNew3, SPLIT *psplit,
	PGTYP pgtyp, BOOL fAppend, BOOL fSkipMoves );

ERR ErrBTAbandonEmptyPage( FUCB *pfucb, KEY *pkey );

/**********************************************************
/********** MCM STRUCTURES, CONSTANTS and API *************
/**********************************************************
/**/
#define	opInsertItem						0
#define	opDeleteItem						1
#define	opSplitItemList					2

#define	opInsertSon							0
#define	opReplaceSon		 				1
#define	opDeleteSon							2

#define	opHorizontalRightSplitPage		0
#define	opHorizontalLeftSplitPage		1

#define opVerticalSplitPage				0

VOID MCMRightHorizontalPageSplit( FUCB *pfucb,
	PGNO pgnoSplit, PGNO pgnoRight, INT ibSonSplit, BYTE *mpitag );
VOID MCMLeftHorizontalPageSplit( FUCB *pfucb,
	PGNO pgnoSplit, PGNO pgnoNew, INT ibSonSplit, BYTE *mpitag );
VOID MCMVerticalPageSplit(
	FUCB *pfucb,
	BYTE *mpitag,
	PGNO pgnoSplit,
	INT itagSplit,
	PGNO pgnoNew,
	SPLIT *psplit );
VOID MCMDoubleVerticalPageSplit(
	FUCB	*pfucb,
	BYTE	*mpitag,
	PGNO	pgnoSplit,
	INT		itagSplit,
	INT		ibSonDivision,
	PGNO	pgnoNew,
	PGNO	pgnoNew2,
	PGNO	pgnoNew3,
	SPLIT	*psplit );
VOID MCMInsertPagePointer( FUCB *pfucb, PGNO pgnoFather, INT itagFather );
VOID MCMBurstIntrinsic( FUCB *pfucb, PGNO pgnoFather, INT itagFather, PGNO pgnoNew, INT itagNew );

#define FFUCBRecordCursor( pfucb ) (						\
		( pfucb )->u.pfcb != pfcbNil ?						\
		FFCBClusteredIndex( ( pfucb )->u.pfcb ) : fFalse )

#ifdef		NOLOG		/* logging disabled	*/

#define ErrLGSplitL( ppib, pcsrPagePointer, psplit, pgtyp )	0
#define ErrLGSplitR( ppib, pcsrPagePointer, psplit, pgtyp )	0
#define ErrLGSplitV( ppib, psplit, pgtyp )	0
#define ErrLGAddendR( pfucb, pcsrPagePointer, psplit, newpagetype ) 0

#else

ERR ErrLGSplitL(
	FUCB *pfucb,
	CSR *pcsrPagePointer,
	SPLIT *psplit,
	PGTYP newpagetype );

ERR ErrLGSplitR(
	FUCB *pfucb,
	CSR *pcsrPagePointer,
	SPLIT *psplit,
	PGTYP newpagetype );

ERR ErrLGSplitV(
	FUCB *pfucb,
	SPLIT *psplit,
	PGTYP newpagetype );

ERR ErrLGAddendR(
	FUCB *pfucb,
	CSR *pcsrPagePointer,
	SPLIT *psplit,
	PGTYP newpagetype );

#endif