summaryrefslogtreecommitdiff
path: root/src/core/xbixndx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/xbixndx.cpp')
-rwxr-xr-xsrc/core/xbixndx.cpp2820
1 files changed, 0 insertions, 2820 deletions
diff --git a/src/core/xbixndx.cpp b/src/core/xbixndx.cpp
deleted file mode 100755
index 9d946dd..0000000
--- a/src/core/xbixndx.cpp
+++ /dev/null
@@ -1,2820 +0,0 @@
-/* xbixndx.cpp
-
-XBase64 Software Library
-
-Copyright (c) 1997,2003,2014,2022 Gary A Kunkel
-
-The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
-
-Email Contact:
-
- XDB-devel@lists.sourceforge.net
- XDB-users@lists.sourceforge.net
-
-*/
-
-#include "xbase.h"
-
-#ifdef XB_NDX_SUPPORT
-
-namespace xb{
-
-
-/***********************************************************************/
-//! @brief Class constructor.
-/*!
- \param dbf Pointer to dbf instance.
-*/
-
-xbIxNdx::xbIxNdx( xbDbf *dbf ) : xbIx( dbf ){
- ndxTag = (xbNdxTag *) calloc( 1, sizeof( xbNdxTag ));
- SetBlockSize( XB_NDX_BLOCK_SIZE );
- cNodeBuf = (char *) malloc( XB_NDX_BLOCK_SIZE );
-}
-/***********************************************************************/
-//! @brief Class Destructor.
-xbIxNdx::~xbIxNdx(){
- if( ndxTag ){
- ndxTag->npNodeChain = FreeNodeChain( ndxTag->npNodeChain );
- if( ndxTag->cpKeyBuf )
- free( ndxTag->cpKeyBuf );
- if( ndxTag->cpKeyBuf2 )
- free( ndxTag->cpKeyBuf2 );
- if( ndxTag->exp ){
- delete ndxTag->exp;
- ndxTag->exp = NULL;
- }
- ndxTag->sKeyExpression.Set( NULL );
- ndxTag->sTagName.Set( NULL );
- free( ndxTag );
- ndxTag = NULL;
- }
- if( cNodeBuf )
- free( cNodeBuf );
-}
-/***********************************************************************/
-//! @brief Add key.
-/*!
- Add key. If this is a unique index, this logic assumes the duplicate
- check logic was already done.
-
- \param vpTag Tag to update.
- \param ulRecNo Record number to add key for.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::AddKey( void * vpTag, xbUInt32 ulRecNo ){
-
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
- if( GetUniqueKeyOpt() == XB_EMULATE_DBASE && npTag->bFoundSts )
- return XB_NO_ERROR;
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbInt16 iHeadNodeUpdateOpt = 2;
-
-
- try{
-
- if(( iRc = xbIxNdx::KeySetPosAdd( npTag, ulRecNo )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- xbInt32 lKeyCnt = GetKeyCount( npTag->npCurNode );
- if( lKeyCnt < npTag->iKeysPerBlock ){
- // Section A - add key to appropriate position if space available
- if(( iRc = InsertNodeL( npTag, npTag->npCurNode, npTag->npCurNode->iCurKeyNo, npTag->cpKeyBuf, ulRecNo )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
-
- } else {
- // land here with a full leaf node
- iHeadNodeUpdateOpt = 1;
- // section B - split the leaf node
- xbIxNode * npRightNode = AllocateIxNode( GetBlockSize() + (xbUInt32) npTag->iKeyItemLen, 1 );
- if( !npRightNode ){
- iErrorStop = 120;
- iRc = XB_NO_MEMORY;
- throw iRc;
- }
- if(( iRc = SplitNodeL( npTag, npTag->npCurNode, npRightNode, npTag->npCurNode->iCurKeyNo, npTag->cpKeyBuf, ulRecNo )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- xbUInt32 ulTempBlockNo = npRightNode->ulBlockNo;
-
- // section C - go up the tree, splitting nodes as necessary
- xbIxNode * npParent = npTag->npCurNode->npPrev;
- while( npParent && GetKeyCount( npParent ) >= npTag->iKeysPerBlock ){
- npRightNode = FreeNodeChain( npRightNode );
- npRightNode = AllocateIxNode( GetBlockSize() + (xbUInt32) npTag->iKeyItemLen, 1 );
- if( !npRightNode ){
- iErrorStop = 140;
- iRc = XB_NO_MEMORY;
- throw iRc;
- }
- if(( iRc = SplitNodeI( npTag, npParent, npRightNode, npParent->iCurKeyNo, ulTempBlockNo )) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
- ulTempBlockNo = npRightNode->ulBlockNo;
- npTag->npCurNode = npParent;
- npParent = npParent->npPrev;
- }
-
- // section D - if cur node is split root, create new root
- if( npTag->npCurNode->ulBlockNo == npTag->ulRootBlock ){
- // xbase->WriteLogMessage( "Section d" );
- if(( iRc = AddKeyNewRoot( npTag, npTag->npCurNode, npRightNode )) != XB_NO_ERROR ){
- iErrorStop = 160;
- throw iRc;
- }
- npRightNode = FreeNodeChain( npRightNode );
-
- } else {
- // else section E, put key in parent
- if(( iRc = InsertNodeI( vpTag, npParent, npParent->iCurKeyNo, npRightNode->ulBlockNo )) != XB_NO_ERROR ){
- iErrorStop = 170;
- throw iRc;
- }
- npRightNode = FreeNodeChain( npRightNode );
- }
- }
-
- // update the header
- if(( iRc = WriteHeadBlock( iHeadNodeUpdateOpt )) != XB_NO_ERROR ){
- iErrorStop = 180;
- throw iRc;
- }
-
- // ---- free whatever is left of the node chain here, this might not be right, might need to restore it to
- // the point right after SetKeyPosAdd
- npTag->npNodeChain = FreeNodeChain( ndxTag->npNodeChain );
- npTag->npCurNode = NULL;
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::AddKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/***********************************************************************/
-//! @brief Add new root node.
-/*!
- \param npTag Tag to update.
- \param npLeft Left node.
- \param npRight Right node.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-xbInt16 xbIxNdx::AddKeyNewRoot( xbNdxTag *npTag, xbIxNode *npLeft, xbIxNode *npRight ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbString sMsg;
- char *pLastKey = NULL;
-
- try{
- xbIxNode *npRoot = AllocateIxNode( GetBlockSize() + (xbUInt32) npTag->iKeyItemLen, 1 );
- if( !npRoot ){
- iErrorStop = 100;
- iRc = XB_NO_MEMORY;
- throw iRc;
- }
- npTag->ulRootBlock = npRoot->ulBlockNo;
- pLastKey = (char *) malloc( (size_t) ndxTag->iKeyLen );
- if(( iRc = GetLastKeyForBlockNo( npTag, npLeft->ulBlockNo, pLastKey )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- char * pTrg = npRoot->cpBlockData;
-
- // set no of keys to 1
- ePutUInt32( pTrg, 1 );
-
- // set the left node number
- pTrg += 4;
- ePutUInt32( pTrg, npLeft->ulBlockNo );
-
- // set the key
- pTrg+= 8;
- memcpy( pTrg, pLastKey, (size_t) npTag->iKeyLen );
-
- // set the right node number
- pTrg+= (npTag->iKeyItemLen - 8);
- ePutUInt32( pTrg, npRight->ulBlockNo );
-
- // write out the block
- if(( iRc = WriteBlock( npRoot->ulBlockNo, GetBlockSize(), npRoot->cpBlockData )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- if( pLastKey )
- free( pLastKey );
- NodeFree( npRoot );
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::AddKeyNewRoot() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- if( pLastKey )
- free( pLastKey );
- }
- return iRc;
-}
-/***********************************************************************/
-//! @brief Append node to node chain.
-/*!
- Append a node to the current node chain for a given tag.
-
- \param vpTag Tag to update.
- \param npNode Node to add to node chain.
- \returns void
-*/
-void xbIxNdx::AppendNodeChain( void *vpTag, xbIxNode * npNode ){
-
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- if( npTag->npNodeChain == NULL ){
- npTag->npNodeChain = npNode;
- npTag->npCurNode = npNode;
- } else {
- npNode->npPrev = npTag->npCurNode;
- npTag->npCurNode->npNext = npNode;
- npTag->npCurNode = npNode;
- }
- // time stamp the node chain
- GetFileMtime( npTag->tNodeChainTs );
-}
-
-/***********************************************************************/
-//! @brief Allocate a node.
-/*!
- \param ulBufSize Buffer size.
- \param iOpt 0 - Don't update the node block number on the node.
- 1 - Set node block number to the next available block number.
- \returns Pointer to new node.
-*/
-
-xbIxNode * xbIxNdx::AllocateIxNode( xbUInt32 ulBufSize, xbInt16 iOpt ){
- xbIxNode *n = xbIx::AllocateIxNode( ulBufSize );
- if( n && iOpt == 1 ) n->ulBlockNo = ndxTag->ulTotalBlocks++;
- return n;
-}
-/***********************************************************************/
-//! @brief Check for duplicate key.
-/*!
- \param vpTag Tag to check.
- \returns XB_KEY_NOT_UNIQUE<br>XB_NO_ERROR
-*/
-xbInt16 xbIxNdx::CheckForDupKey( void *vpTag )
-{
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbNdxTag *npTag = (xbNdxTag *) vpTag;
- npTag->bFoundSts = xbFalse;
- try{
- if( GetUnique()){
- if( npTag->iKeySts == XB_ADD_KEY || npTag->iKeySts == XB_UPD_KEY )
- if( KeyExists( vpTag )){
- if( GetUniqueKeyOpt() == XB_EMULATE_DBASE ){
- npTag->bFoundSts = xbTrue;
- return 0;
- } else {
- return XB_KEY_NOT_UNIQUE;
- }
- }
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::CheckForDupKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/***********************************************************************/
-//! @brief Check tag integrity.
-/*!
- Check a tag for accuracy.
-
- \param vpTag Tag to create key for.
- \param iOpt Output message destination<br>
- 0 = stdout<br>
- 1 = Syslog<br>
- 2 = Both<br>
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-xbInt16 xbIxNdx::CheckTagIntegrity( void *vpTag, xbInt16 iOpt ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iRc2;
- xbInt16 iRc3;
- xbInt16 iErrorStop = 0;
- xbUInt32 ulIxCnt = 0;
- xbUInt32 ulThisRecNo = 0;
- xbUInt32 ulPrevRecNo = 0;
- xbBool bDone = false;
- xbString sMsg;
- char cKeyType;
- char *pPrevKeyBuf = NULL;
-
- #ifdef XB_LOCKING_SUPPORT
- xbBool bLocked = xbFalse;
- #endif
-
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- try{
- #ifdef XB_LOCKING_SUPPORT
- if( dbf->GetAutoLock() && !dbf->GetTableLocked() ){
- if(( iRc = dbf->LockTable( XB_LOCK )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- bLocked = xbTrue;
- }
- #endif
-
- memset( npTag->cpKeyBuf2, 0x00, (size_t) npTag->iKeyLen );
- cKeyType = GetKeyType( vpTag );
-
- sMsg.Sprintf( "Checking index type [%c]", cKeyType );
- xbase->WriteLogMessage( sMsg, iOpt );
-
- pPrevKeyBuf = (char *) calloc( 1, (size_t) ndxTag->iKeyLen );
-
- // for each key in the index, make sure it is trending in the right direction
- iRc = GetFirstKey( vpTag, 0 );
- while( iRc == XB_NO_ERROR && !bDone ){
- ulIxCnt++;
- iRc = GetNextKey( vpTag, 0 );
- if( iRc == XB_NO_ERROR ){
- // compare this key to prev key
- iRc2 = CompareKey( cKeyType, GetKeyData( npTag->npCurNode, npTag->npCurNode->iCurKeyNo, npTag->iKeyItemLen ),
- pPrevKeyBuf, (size_t) npTag->iKeyLen );
-
- if( iRc2 < 0 ){
- sMsg.Sprintf( "Key sequence error at key number [%ld].", ulIxCnt );
- xbase->WriteLogMessage( sMsg, iOpt );
- iErrorStop = 110;
- iRc = XB_INVALID_INDEX;
- throw iRc;
- }
-
- ulThisRecNo = 0;
- if(( iRc3 = GetDbfPtr( vpTag, npTag->npCurNode->iCurKeyNo, npTag->npCurNode, ulThisRecNo )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc3;
- }
-
- if( iRc2 == 0 && (ulThisRecNo <= ulPrevRecNo )){
- sMsg.Sprintf( "Dbf record number sequence error at key number [%ld].", iOpt );
- xbase->WriteLogMessage( sMsg, iOpt );
- iErrorStop = 130;
- iRc = XB_INVALID_INDEX;
- throw iRc;
- }
- // save this key info to prev key
- memcpy( pPrevKeyBuf, GetKeyData( npTag->npCurNode, npTag->npCurNode->iCurKeyNo, npTag->iKeyItemLen ), (size_t) npTag->iKeyLen );
- ulPrevRecNo = ulThisRecNo;
- }
- }
-
- // verify the index count matches the tag count
- xbUInt32 ulDbfCnt = 0;
- if(( iRc = dbf->GetRecordCnt( ulDbfCnt )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
-
- if( GetUniqueKeyOpt() == XB_EMULATE_DBASE && GetUnique( vpTag )){
- // Can't compare counts if using XB_EMULATE_DBASE and it's a unique index
- } else {
- if( ulDbfCnt != ulIxCnt ){
- sMsg.Sprintf( "CheckTagIntegrity() Index entry count [%ld] does not match dbf record count [%ld]", ulIxCnt, ulDbfCnt );
- xbase->WriteLogMessage( sMsg, iOpt );
- iErrorStop = 150;
- iRc = XB_INVALID_INDEX;
- throw iRc;
- }
-
- // verify each record in the dbf file has a corresponding index entry
- xbUInt32 j = 0;
- while( j < ulDbfCnt ){
- if(( iRc = dbf->GetRecord( ++j )) != XB_NO_ERROR ){
- iErrorStop = 160;
- throw iRc;
- }
- if(( iRc = FindKeyForCurRec( vpTag )) != XB_NO_ERROR ){
- ulThisRecNo = j;
- iErrorStop = 170;
- throw iRc;
- }
- }
- sMsg.Sprintf( "CheckTagIntegrity() Index entry count [%ld] matches dbf record count [%ld]", ulIxCnt, ulDbfCnt );
- xbase->WriteLogMessage( sMsg, iOpt );
- }
- if( pPrevKeyBuf )
- free( pPrevKeyBuf );
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::CheckTagIntegrity() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg, iOpt );
- xbase->WriteLogMessage( GetErrorMessage( iRc ), iOpt );
- if( pPrevKeyBuf )
- free( pPrevKeyBuf );
-
- if( iErrorStop == 170 ){
- sMsg.Sprintf( "xbIxNdx::CheckTagIntegrity() Missing index entry for record [%d]", ulThisRecNo );
- xbase->WriteLogMessage( sMsg, iOpt );
- }
- }
-
- #ifdef XB_LOCKING_SUPPORT
- if( bLocked ){
- dbf->LockTable( XB_UNLOCK );
- }
- #endif
- return iRc;
-
-}
-/***********************************************************************/
-//! @brief Create key for tag.
-/*!
- Append a node to the current node chain for a given tag.
-
- \param vpTag Tag to create key for.
- \param iOpt 0 = Build a key for FindKey usage, only rec buf 0.<br>
- 1 = Append Mode, Create key for an append, only use rec buf 0, set updated switch.<br>
- 2 = Update Mode, Create old version and new version keys, check if different, set update switch appropriately.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::CreateKey( void * vpTag, xbInt16 iOpt ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- try{
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- if(( iRc = npTag->exp->ProcessExpression( 0 )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- if( npTag->exp->GetReturnType() == XB_EXP_CHAR ){
- npTag->exp->GetStringResult( npTag->cpKeyBuf, (xbUInt32) npTag->iKeyLen );
- }
- else if( npTag->exp->GetReturnType() == XB_EXP_NUMERIC ){
- xbDouble d;
- npTag->exp->GetNumericResult( d );
- memcpy( npTag->cpKeyBuf, &d, 8 );
- }
- else if( npTag->exp->GetReturnType() == XB_EXP_DATE ){
- xbDouble d;
- npTag->exp->GetNumericResult( d );
- memcpy( npTag->cpKeyBuf, &d, 8 );
- }
-
- npTag->iKeySts = 0;
- if( iOpt == 1 )
- npTag->iKeySts = XB_ADD_KEY;
-
- else if( iOpt == 2 ){
- if(( iRc = npTag->exp->ProcessExpression( 1 )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- if( npTag->exp->GetReturnType() == XB_EXP_CHAR ){
- npTag->exp->GetStringResult( npTag->cpKeyBuf2, (xbUInt32) npTag->iKeyLen );
- } else if( npTag->exp->GetReturnType() == XB_EXP_NUMERIC || npTag->exp->GetReturnType() == XB_EXP_DATE ){
- xbDouble d;
- npTag->exp->GetNumericResult( d );
- memcpy( npTag->cpKeyBuf2, &d, 8 );
- }
- if( memcmp( npTag->cpKeyBuf, npTag->cpKeyBuf2, (size_t) npTag->iKeyLen ))
- npTag->iKeySts = XB_UPD_KEY;
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::CreateKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-/***********************************************************************/
-//! @brief Create new tag.
-/*!
- This routine creates a new tag. Since NDX files have only one tag,
- this creates a new NDX file.
-
- \param sName Tag Name, including .NDX suffix
- \param sKey Key Expression
- \param sFilter Filter expression. Not supported by NDX indices.
- \param iDescending Not supported by NDX indices.
- \param iUnique xbtrue - Unique.<br>xbFalse - Not unique.
- \param iOverLay xbTrue - Overlay if file already exists.<br>xbFalse - Don't overlay.
- \param vpTag Output from method Pointer to vptag pointer.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::CreateTag( const xbString &sName, const xbString &sKey,
- const xbString &, xbInt16, xbInt16 iUnique, xbInt16 iOverLay, void **vpTag ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbNdxTag *npTag = ndxTag;
- *vpTag = ndxTag;
-
- try{
- //xbString sMsg;
- SetFileName( sName );
-
- if( FileExists() && !iOverLay )
- return XB_FILE_EXISTS;
-
- if( FileIsOpen()){
- if(( iRc = xbTruncate(0)) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- if(( iRc = xbFclose()) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- npTag->npNodeChain = FreeNodeChain( npTag->npNodeChain );
- npTag->npCurNode = NULL;
- npTag->sKeyExpression.Set( "" );
-
- if( npTag->cpKeyBuf ){
- free( npTag->cpKeyBuf );
- npTag->cpKeyBuf = NULL;
- }
- if( npTag->cpKeyBuf2 ){
- free( npTag->cpKeyBuf2 );
- npTag->cpKeyBuf2 = NULL;
- }
- }
- if(( iRc = xbFopen( "w+b", dbf->GetShareMode())) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
-
- //set up the key expression
- npTag->exp = new xbExp( dbf->GetXbasePtr());
- if(( iRc = npTag->exp->ParseExpression( dbf, sKey )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
-
- switch( npTag->exp->GetReturnType()){
- case XB_EXP_CHAR:
- npTag->cKeyType = 'C';
- npTag->iKeyType = 0;
- npTag->iKeyLen = npTag->exp->GetResultLen();
- break;
-
- case XB_EXP_NUMERIC:
- npTag->cKeyType = 'F';
- npTag->iKeyType = 1;
- npTag->iKeyLen = 8;
- break;
-
- case XB_EXP_DATE:
- npTag->cKeyType = 'D';
- npTag->iKeyType = 1;
- npTag->iKeyLen = 8;
- break;
-
- default:
- iErrorStop = 140;
- iRc = XB_INVALID_INDEX;
- throw iRc;
- }
-
- npTag->iUnique = iUnique;
- npTag->ulRootBlock = 1L;
- npTag->ulTotalBlocks = 2l;
- npTag->sKeyExpression = sKey;
-
- GetFileNamePart( npTag->sTagName );
-
- if( npTag->iKeyLen > 100 ){
- iErrorStop = 150;
- throw iRc;
- }
-
- npTag->iKeyItemLen = npTag->iKeyLen + 8;
- while(( npTag->iKeyItemLen % 4 )!= 0 ) npTag->iKeyItemLen++;
-
- npTag->iKeysPerBlock = (xbInt16) (GetBlockSize() - 8 ) / npTag->iKeyItemLen;
- ndxTag->cpKeyBuf = (char *) malloc( (size_t) ndxTag->iKeyLen );
- ndxTag->cpKeyBuf2 = (char *) malloc( (size_t) ndxTag->iKeyLen );
-
- if(( iRc = WriteHeadBlock(0)) != XB_NO_ERROR ){
- iErrorStop = 160;
- throw iRc;
- }
-
- //write out block binary zeroes
- char buf[512];
- memset( buf, 0x00, 512 );
- if(( iRc = xbFwrite( buf, 1, 512 )) != XB_NO_ERROR ){
- iErrorStop = 170;
- throw iRc;
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::CreateTag() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/***********************************************************************/
-//! @brief Delete a key.
-/*!
- This routine deletes a key from a supplied node.
- \param vpTag Tag to delete key on.
- \param npNode Node to delete key on.
- \param iSlotNo Slot number of key to delete.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::DeleteFromNode( void *vpTag, xbIxNode * npNode, xbInt16 iSlotNo )
-{
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- try{
-
- xbInt32 lKeyCnt = GetKeyCount( npNode );
- xbInt16 iLen = (lKeyCnt - iSlotNo - 1) * npTag->iKeyItemLen;
- if( !IsLeaf( vpTag, npNode ))
- iLen += 4;
-
- if( iLen > 0 ){
- char *pTrg = npNode->cpBlockData;
- pTrg += (4 + (npTag->iKeyItemLen * (iSlotNo)) ); //lTrgPos;
- char *pSrc = pTrg;
- pSrc += npTag->iKeyItemLen;
- memmove( pTrg, pSrc, (size_t) iLen );
- }
-
- // set the new number of keys
- ePutUInt32( npNode->cpBlockData, (xbUInt32) lKeyCnt - 1 );
-
- // write out the block
- if(( iRc = WriteBlock( npNode->ulBlockNo, GetBlockSize(), npNode->cpBlockData )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::DeleteFromNode() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return XB_NO_ERROR;
-}
-
-/***********************************************************************/
-//! @brief Delete a key.
-/*!
- This routine deletes a key. It assumes the key to delete
- is the current key in the node chain.
-
- \param vpTag Tag to delete key on.
-
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::DeleteKey( void *vpTag ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- // save copy of node chain to reset to after delete completed
- xbIxNode *npSaveNodeChain = npTag->npNodeChain;
- npTag->npNodeChain = NULL;
- xbIxNode * npSaveCurNode = npTag->npCurNode;
-
- try{
-
- xbString sMsg;
-
- if(( iRc = xbIxNdx::KeySetPosDel( npTag )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- // Delete key needs to handle two scenarios
- // 1 - if the delete is on the only key of a leaf node, then traverse up the tree, trimming as needed
- // 2 - if the last key on a node is deleted, and the key value is not the same as the prev key value
- // go up the tree looking for an interior node needing updated key value
-
- xbInt32 lOrigKeyCnt = GetKeyCount( npTag->npCurNode );
- if(( iRc = DeleteFromNode( npTag, npTag->npCurNode, npTag->npCurNode->iCurKeyNo )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
-
- if( lOrigKeyCnt == 1 ){
- // scenario 1
- xbBool bDone = xbFalse;
- xbBool bIsLeaf = xbFalse;
- xbInt32 lKeyCnt;
- npTag->npCurNode = npTag->npCurNode->npPrev;
-
- while( npTag->npCurNode && !bDone ){
- lKeyCnt = GetKeyCount( npTag->npCurNode );
- bIsLeaf = IsLeaf( npTag, npTag->npCurNode );
- if( lKeyCnt > 0 ){
- if(( iRc = DeleteFromNode( npTag, npTag->npCurNode, npTag->npCurNode->iCurKeyNo )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- }
- if( (bIsLeaf && lKeyCnt > 1) || (!bIsLeaf && lKeyCnt > 0) )
- bDone = xbTrue;
- else
- npTag->npCurNode = npTag->npCurNode->npPrev;
- }
- } else if( npTag->npCurNode->iCurKeyNo == (xbUInt32) lOrigKeyCnt - 1 ){
-
- // scenario 2
- // if last two keys identical, then nothing to do, else go up looking for a key to change
- if( memcmp( GetKeyData( npTag->npCurNode, npTag->npCurNode->iCurKeyNo, npTag->iKeyItemLen ),
- GetKeyData( npTag->npCurNode, npTag->npCurNode->iCurKeyNo-1, npTag->iKeyItemLen ),
- (size_t) npTag->iKeyLen )){
-
- xbIxNode *pNode = npTag->npCurNode->npPrev;
- char *pSrc = GetKeyData( npTag->npCurNode, npTag->npCurNode->iCurKeyNo-1, npTag->iKeyItemLen );
-
- while( pNode && pNode->ulBlockNo != npTag->ulRootBlock && pNode->iCurKeyNo == (xbUInt32) GetKeyCount( pNode ) )
- pNode = pNode->npPrev;
- if( pNode ){
- if( pNode->iCurKeyNo < (xbUInt32) GetKeyCount( pNode )){
- char *pTrg = pNode->cpBlockData;
- pTrg += 12 + (pNode->iCurKeyNo * (xbUInt32) npTag->iKeyItemLen);
- for( xbInt16 i = 0; i < npTag->iKeyLen; i++ )
- *pTrg++ = *pSrc++;
-
- // write out the block
- if(( iRc = WriteBlock( pNode->ulBlockNo, GetBlockSize(), pNode->cpBlockData )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- }
- }
- }
- }
-
- // restore node chain to pre delete status (which should be post add status)
- npTag->npNodeChain = FreeNodeChain( npTag->npNodeChain );
- npTag->npNodeChain = npSaveNodeChain;
- npTag->npCurNode = npSaveCurNode;
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::DeleteKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- if( npSaveNodeChain ){
- npTag->npNodeChain = npSaveNodeChain;
- npSaveNodeChain = FreeNodeChain( npSaveNodeChain );
- npTag->npCurNode = npSaveCurNode;
- }
- }
- return iRc;
-}
-
-
-/***********************************************************************/
-//! @brief Delete tag.
-/*!
- In the case of an ndx tag, it deletes the ndx file as it contains
- only one tag.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::DeleteTag( void * ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- //xbNdxTag * npTag;
- //vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- try{
-
- // if open, close it
- if( FileIsOpen()){
- if(( iRc = Close()) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- }
- // delete file
- if(( iRc = xbRemove()) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::DeleteTag() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-/***********************************************************************/
-#ifdef XB_DEBUG_SUPPORT
-
-//! @brief Dump a block for a given tag.
-/*!
- Dump blocks for given tag for debugging purposes.
- \param iOpt Output message destination<br>
- 0 = stdout<br>
- 1 = Syslog<br>
- 2 = Both<br>
- \param vpTag - Not required for single tag NDX files.
- \returns void
-*/
-
-xbInt16 xbIxNdx::DumpTagBlocks( xbInt16 iOpt, void * ){
-
- xbInt16 iRc = 0;
- xbInt16 iErrorStop = 0;
- xbUInt32 lNoOfKeys;
- char *p;
- xbString s;
- xbBool bIsLeaf = false;
-
- try{
- if( !FileIsOpen()){
- iRc = XB_NOT_OPEN;
- iErrorStop = 100;
- throw iRc;
- }
-
- xbUInt32 ulStartBlock;
- xbUInt32 ulEndBlock;
- ulStartBlock = 1;
- ulEndBlock = ndxTag->ulTotalBlocks;
-
- for( xbUInt32 lBlk = ulStartBlock; lBlk < ulEndBlock; lBlk++ ){
-
- memset( cNodeBuf, 0x00, XB_NDX_BLOCK_SIZE );
- if(( iRc = ReadBlock( lBlk, XB_NDX_BLOCK_SIZE, cNodeBuf )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- p = cNodeBuf;
- lNoOfKeys = eGetUInt32( p );
-
- if( eGetUInt32( p + 4 ) > 0 ){
- bIsLeaf = false;
- s.Sprintf( "Node # %ld - Interior Node - Key Type [%c] Key Count [%ld]", lBlk, ndxTag->cKeyType, lNoOfKeys );
- } else {
- bIsLeaf = true;
- s.Sprintf( "Node # %ld - Leaf Node - Key Type [%c] Key count [%ld]", lBlk, ndxTag->cKeyType, lNoOfKeys );
- }
- xbase->WriteLogMessage( s, iOpt );
- xbase->WriteLogMessage( "Key Child Dbf Rec Key", iOpt );
- p += 4;
- xbUInt32 ulLeftBranch;
- xbUInt32 ulRecNo;
- xbString sKey;
- xbDouble d;
-
- xbUInt32 l;
- for( l = 0; l < lNoOfKeys; l++ ){
- ulLeftBranch = eGetUInt32( p );
- p+= 4;
- ulRecNo = eGetUInt32( p );
- p+= 4;
- if( ndxTag->cKeyType == 'C' ){
- sKey.Assign( p, 1, (xbUInt32) ndxTag->iKeyLen );
- } else if( ndxTag->cKeyType == 'D' ){
- xbInt32 lDate = (xbInt32) eGetDouble( p );
- xbDate dt( lDate );
- //xbString s2;
- //dt.JulToDate8( lDate, s2 );
- sKey.Sprintf( "%ld - %s", lDate, dt.Str());
- } else {
- d = eGetDouble( p );
- sKey.Sprintf( "%f", d );
- }
- p+= (ndxTag->iKeyItemLen-8);
-
- s.Sprintf( "%3d %9d %9d %s", l+1, ulLeftBranch, ulRecNo, sKey.Str() );
- xbase->WriteLogMessage( s, iOpt );
- }
- if( !bIsLeaf ){
- ulLeftBranch = eGetUInt32( p );
- s.Sprintf( "%3d %9d", l+1, ulLeftBranch );
- xbase->WriteLogMessage( s, iOpt );
- }
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::DumpTagBlocks() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-/***********************************************************************/
-//! @brief Dump index file header.
-/*!
- Dump a index file header for debugging purposes.
- \param iOpt Output message destination<br>
- 0 = stdout<br>
- 1 = Syslog<br>
- 2 = Both<br>
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::DumpHeader( xbInt16 iOpt, xbInt16 ){
- xbString s;
- xbInt16 iRc;
-
- if(( iRc = ReadHeadBlock( 1 )) != XB_NO_ERROR )
- return iRc;
-
- s.Sprintf( "Index Header Node for %s", GetFileName().Str());
- xbase->WriteLogMessage( s, iOpt );
- s.Sprintf( "--------------------------------" );
- xbase->WriteLogMessage( s, iOpt );
- s.Sprintf( "Root block = %ld", ndxTag->ulRootBlock );
- xbase->WriteLogMessage( s, iOpt );
- s.Sprintf( "Total blocks = %ld", ndxTag->ulTotalBlocks );
- xbase->WriteLogMessage( s, iOpt );
- s.Sprintf( "Key types = %c,%d", ndxTag->cKeyType, ndxTag->iKeyType );
- xbase->WriteLogMessage( s, iOpt );
- s.Sprintf( "Key Length = %d", ndxTag->iKeyLen );
- xbase->WriteLogMessage( s, iOpt );
- s.Sprintf( "Keys Per Block = %d", ndxTag->iKeysPerBlock );
- xbase->WriteLogMessage( s, iOpt );
- s.Sprintf( "Key Item Len = %ld", ndxTag->iKeyItemLen );
- xbase->WriteLogMessage( s, iOpt);
- s.Sprintf( "Serial No = %d", ndxTag->cSerNo );
- xbase->WriteLogMessage( s, iOpt);
- s.Sprintf( "Unique = %d", ndxTag->iUnique );
- xbase->WriteLogMessage( s, iOpt );
- s.Sprintf( "KeyExpression = %s", ndxTag->sKeyExpression.Str() );
- xbase->WriteLogMessage( s, iOpt );
- return XB_NO_ERROR;
-}
-/***********************************************************************/
-//! @brief Dump the index for a tag.
-/*!
- Stub.
- \returns XB_NO_ERROR
-*/
-xbInt16 xbIxNdx::DumpIxForTag( void *, xbInt16 )
-{
- return XB_NO_ERROR;
-}
-/***********************************************************************/
-//! @brief Dump the index node chain.
-/*!
- Dump the index node chain for debugging purposes.
- \param vpTag Tag of node chain to dump.
- \param iOpt Output message destination<br>
- 0 = stdout<br>
- 1 = Syslog<br>
- 2 = Both<br>
- \returns void
-*/
-void xbIxNdx::DumpIxNodeChain( void *vpTag, xbInt16 iOpt ) const
-{
-
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- xbString s( "Dump Node Chain" );
- xbase->WriteLogMessage( s, iOpt );
-
- if( npTag->npNodeChain ){
- xbIxNode *n = npTag->npNodeChain;
- xbInt16 iCtr = 0;
- char cLeaf;
- s.Sprintf( "Cnt\tThis Prev Next CurKeyNo BlockNo NoOfKeys Type" );
- xbase->WriteLogMessage( s, iOpt );
- while( n ){
- IsLeaf( vpTag, n ) ? cLeaf = 'L' : cLeaf = 'I';
- s.Sprintf( "%d\t%08x %08x %08x %08d %08d %08d %c",
- iCtr++, n, n->npPrev, n->npNext, n->iCurKeyNo,
- n->ulBlockNo, eGetUInt32( n->cpBlockData ), cLeaf );
- xbase->WriteLogMessage( s, iOpt );
- n = n->npNext;
- }
- } else {
- s = "Empty Node Chain";
- xbase->WriteLogMessage( s, iOpt );
- }
-}
-/***********************************************************************/
-//! @brief Dump node.
-/*!
- Dump a node for debugging purposes.
- \param vpTag Tag of node chain to dump.
- \param pNode Node to dump.
- \param iOpt Output message destination<br>
- 0 = stdout<br>
- 1 = Syslog<br>
- 2 = Both<br>
- \returns XB_INVALID_OBJECT<br>XB_NO_ERROR
-*/
-
-xbInt16 xbIxNdx::DumpNode( void *vpTag, xbIxNode *pNode, xbInt16 iOpt ) const
-{
- xbString s;
- xbString sKey;
- xbUInt32 lLeftBranch;
- xbUInt32 lRecNo;
- xbDouble d;
-
- if( !pNode )
- return XB_INVALID_OBJECT;
-
- xbIx::DumpNode( vpTag, pNode, iOpt );
-
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- xbUInt32 lNoOfKeys = eGetUInt32( pNode->cpBlockData );
- xbBool bIsLeaf = IsLeaf( vpTag, pNode );
-
- if( bIsLeaf )
- xbase->WriteLogMessage( "Leaf node", iOpt );
- else
- xbase->WriteLogMessage( "Interior node", iOpt );
-
- s.Sprintf( "Key type = [%c] No Of Keys =[%d] Prev =[%x] Next =[%x]", npTag->cKeyType, lNoOfKeys, pNode->npPrev, pNode->npNext );
- xbase->WriteLogMessage( s, iOpt );
-
- char *p = pNode->cpBlockData;
- p += 4;
-
- xbUInt32 l;
- for( l = 0; l < lNoOfKeys; l++ ){
-
- lLeftBranch = eGetUInt32( p );
- p+= 4;
- lRecNo = eGetUInt32( p );
- p+= 4;
-
- if( npTag->cKeyType == 'C' ){
- sKey.Assign( p, 1, (xbUInt32) npTag->iKeyLen );
- } else if( npTag->cKeyType == 'D' ){
- xbInt32 lDate = (xbInt32) eGetDouble( p );
- xbDate dt( lDate );
- sKey.Sprintf( "%ld - %s", lDate, dt.Str());
- } else {
- d = eGetDouble( p );
- sKey.Sprintf( "%f", d );
- }
- p+= (npTag->iKeyItemLen-8);
- s.Sprintf( "%3d %9d %9d %s", l+1, lLeftBranch, lRecNo, sKey.Str() );
- xbase->WriteLogMessage( s, iOpt );
- }
- if( !bIsLeaf ){
- lLeftBranch = eGetUInt32( p );
- s.Sprintf( "%3d %9d", l+1, lLeftBranch );
- xbase->WriteLogMessage( s.Str(), iOpt );
- }
- return XB_NO_ERROR;
-}
-#endif
-/***********************************************************************/
-//! @brief Find key
-/*!
- \param vpTag Pointer to tag to search.
- \param vpKey Void pointer to key data to search on.
- \param lSearchKeyLen Length of key to search for.
- \param iRetrieveSw xbTrue - Retrieve the record if key found.<br>
- xbFalse - Don't retrieve record, check for key existence only.
- \returns XB_NO_ERROR - Key found.<br>
- XB_NOT_FOUND - Key not found.<br>
- <a href="xbretcod_8h.html">Return Codes</a>
-*/
-xbInt16 xbIxNdx::FindKey( void *vpTag, const void *vpKey, xbInt32 lSearchKeyLen,
- xbInt16 iRetrieveSw ){
-
-
- xbInt16 iRc = 0;
- xbInt16 iErrorStop = 0;
- xbString sMsg;
- // xbInt16 iFindSts;
- try{
- // clean up any previous table updates before moving on
- if( iRetrieveSw ){
- if( dbf->GetDbfStatus() == XB_UPDATED ){
- if( dbf->GetAutoCommit() == 1 ){
- if(( iRc = dbf->Commit()) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- } else {
- if(( iRc = dbf->Abort()) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- }
- }
- }
-
- xbUInt32 ulNoOfKeys;
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
- char cKeyType = npTag->cKeyType;
-
- if( npTag->npNodeChain ){
-
- // determine if the index has been updated since the last time it was used
- time_t tFileTs;
- if(( iRc = GetFileMtime( tFileTs )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- if( npTag->tNodeChainTs < tFileTs ){
- npTag->npNodeChain = FreeNodeChain( npTag->npNodeChain );
- npTag->npCurNode = NULL;
- if(( iRc = ReadHeadBlock( 1 )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- if(( iRc = GetBlock( npTag, (npTag->ulRootBlock ), 1, (xbUInt32) npTag->iKeyItemLen )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
- } else {
- // pop up the chain looking for appropriate starting point
- xbBool bDone = false;
- xbIxNode * TempIxNode;
- while( npTag->npCurNode && !bDone && npTag->npCurNode->ulBlockNo != npTag->ulRootBlock ){ // not root node
- iRc = CompareKey( cKeyType, vpKey, GetKeyData( npTag->npCurNode, 0, npTag->iKeyItemLen ), (size_t) lSearchKeyLen );
- if( iRc <= 0 ){
- TempIxNode = npTag->npCurNode;
- npTag->npCurNode = npTag->npCurNode->npPrev;
- TempIxNode = FreeNodeChain( TempIxNode );
- } else {
- // get the number of keys on the block and compare the key to the rightmost key
- xbUInt32 ulKeyCtr = eGetUInt32( npTag->npCurNode->cpBlockData ) - 1;
- iRc = CompareKey( cKeyType, vpKey, GetKeyData( npTag->npCurNode, ulKeyCtr, npTag->iKeyItemLen), (size_t) lSearchKeyLen );
-
- if( iRc > 0 ){
- TempIxNode = npTag->npCurNode;
- npTag->npCurNode = npTag->npCurNode->npPrev;
- TempIxNode = FreeNodeChain( TempIxNode );
- } else {
- bDone = true;
- }
- }
- }
- }
- } else {
- if(( iRc = GetBlock( npTag, (npTag->ulRootBlock ), 1, (xbUInt32) npTag->iKeyItemLen )) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
- }
-
-
- // if cur node is the base node and no keys on this node, then the index is empty
- if( npTag->ulRootBlock == npTag->npCurNode->ulBlockNo ){
- ulNoOfKeys = eGetUInt32( npTag->npCurNode->cpBlockData );
- if( ulNoOfKeys == 0 && IsLeaf( npTag, npTag->npCurNode )){
- // iRc = XB_EMPTY;
-
- iRc = XB_NOT_FOUND;
- return iRc;
- }
- }
-
- // should be in the appropriate position in the node chain to continue the search from here
- // run down through the interior nodes
- xbInt16 iSearchRc = 0;
- xbUInt32 ulKeyPtr = 0;
-
- while( !IsLeaf( npTag, npTag->npCurNode ) ){
-
- // get the number of keys on the block and compare the key to the rightmost key
- ulNoOfKeys = eGetUInt32( npTag->npCurNode->cpBlockData );
- if( ulNoOfKeys == 0 ) // interior nodes can have zero keys, just a link to the next lower node
- npTag->npCurNode->iCurKeyNo = 0;
- else
- {
- iRc = CompareKey( cKeyType, vpKey, GetKeyData( npTag->npCurNode, ulNoOfKeys - 1, npTag->iKeyItemLen), (size_t) lSearchKeyLen );
- if( iRc > 0 ){
- npTag->npCurNode->iCurKeyNo = ulNoOfKeys;
- } else {
- npTag->npCurNode->iCurKeyNo = (xbUInt32) BSearchBlock( cKeyType, npTag->npCurNode,
- (xbInt32) npTag->iKeyItemLen, vpKey, (xbInt32) lSearchKeyLen, iSearchRc );
- }
- }
-
- if(( iRc = GetKeyPtr( npTag, npTag->npCurNode->iCurKeyNo, npTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 160;
- throw iRc;
- }
-
- if(( iRc = GetBlock( npTag, ulKeyPtr, 1, (xbUInt32) npTag->iKeyItemLen )) != XB_NO_ERROR ){
- iErrorStop = 170;
- throw iRc;
- }
- }
-
- // should be on a the correct leaf node, it may or may not contain the actual key
- ulNoOfKeys = eGetUInt32( npTag->npCurNode->cpBlockData );
- xbInt16 iCompRc = 0;
-
- if( ulNoOfKeys == 0 ){
- iRc = XB_NOT_FOUND;
- return iRc;
- } else {
-
- iRc = BSearchBlock( cKeyType, npTag->npCurNode, npTag->iKeyItemLen, vpKey, lSearchKeyLen, iCompRc );
-
- // iCompRc
- // 0 found
- // < 0 eof encountered, search key > last key in file
- // > 0 not found, positioned to next key
-
-
- // std::cout << "xbIxNdx::FindKey -Rc = " << iRc << " CompRc = " << iCompRc << " NoOfKeys = " << ulNoOfKeys << " blk no = " << npTag->npCurNode->ulBlockNo << "\n";
-
- if( iCompRc >= 0 ){
- npTag->npCurNode->iCurKeyNo = (xbUInt32) iRc;
- if( iRetrieveSw ){
- xbUInt32 ulKey = npTag->npCurNode->iCurKeyNo;
- if( ulKey >= ulNoOfKeys ) // if position past end of keys, need to go back one and position to last key
- ulKey--;
-
- if(( iRc = GetDbfPtr( vpTag, ulKey, npTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 180;
- throw iRc;
- }
- if(( iRc = dbf->GetRecord( ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 190;
- throw iRc;
- }
- }
- }
- }
-
- if( iCompRc == 0 )
- return XB_NO_ERROR;
- else if( iCompRc > 0 )
- return XB_NOT_FOUND;
- else
- return XB_EOF;
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::FindKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-/***********************************************************************/
-//! @brief Find key for current record
-/*!
- This routine is called when updating a key.
-
- \param vpTag Pointer to tag to search.
- XB_NOT_FOUND Key not found.<br>
- <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::FindKeyForCurRec( void * vpTag )
-{
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- try{
- if(( iRc = CreateKey( vpTag, 0 )) < XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
-
- // find key
- iRc = FindKey( vpTag, npTag->cpKeyBuf, npTag->iKeyLen, 0 );
- if( iRc == XB_NOT_FOUND || iRc == XB_EMPTY || iRc == XB_EOF )
- return iRc;
-
- if( iRc != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
-
- // if keys are unique, and the recrd number matches, then we are good
- if( GetUnique() )
- return XB_NO_ERROR;
-
- // get here if key found and not unique, need to move forward looking for correct rec no
- xbUInt32 ulDbfRecNo = dbf->GetCurRecNo();
- xbBool bKeysMatch = true; // keys match?
- xbBool bCurRecsMatch = false; // cur recod number matches?
- xbUInt32 ulIxRecNo = 0;
- char cKeyType = GetKeyType( vpTag );
-
- if(( iRc = GetDbfPtr( vpTag, npTag->npCurNode->iCurKeyNo, npTag->npCurNode, ulIxRecNo )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- if( ulIxRecNo == ulDbfRecNo )
- bCurRecsMatch = true;
-
- xbInt16 iCompRc;
- while( !bCurRecsMatch && bKeysMatch ){
-
- if(( iRc = GetNextKey( vpTag, 0 )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
-
- // do compare key here
- iCompRc = CompareKey( cKeyType, npTag->cpKeyBuf, GetKeyData( npTag->npCurNode, 0, npTag->iKeyItemLen ), (size_t) npTag->iKeyLen );
- if( iCompRc != 0 )
- bKeysMatch = false;
- else{
- if(( iRc = GetDbfPtr( vpTag, npTag->npCurNode->iCurKeyNo, npTag->npCurNode, ulIxRecNo )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
- if( ulIxRecNo == ulDbfRecNo )
- bCurRecsMatch = true;
- }
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::FindKeyForCurRec() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return XB_NO_ERROR;
-}
-
-/***********************************************************************/
-//! @brief Get dbf record number for given key number.
-/*!
- \param vpTag Tag to retrieve dbf rec number on.
- \param iKeyNo Key number for retrieval
- \param np Pointer to node
- \param ulDbfPtr- Output dbf record number
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-xbInt16 xbIxNdx::GetDbfPtr( void *vpTag, xbInt16 iKeyNo, xbIxNode *np, xbUInt32 &ulDbfPtr ) const {
-
- xbInt16 iRc = 0;
- xbInt16 iErrorStop = 0;
-
- try{
- #ifdef XB_DEBUG_SUPPORT
- // turn this off in production mode for better performance
- xbUInt32 ulNoOfKeys = eGetUInt32 ( np->cpBlockData );
- if( iKeyNo < 0 || iKeyNo > (xbInt16) --ulNoOfKeys ){
- iErrorStop = 100;
- throw XB_INVALID_KEYNO;
- }
- #endif
-
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
- char *p = ( np->cpBlockData);
- p += (8 + (iKeyNo * npTag->iKeyItemLen));
- ulDbfPtr = eGetUInt32 ( p );
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::GetDbfPtr() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-/***********************************************************************/
-//! @brief Get the first key for the given tag.
-/*!
- \param vpTag Tag to retrieve first key on.
- \param iRetrieveSw xbTrue - Retrieve the record on success.<br>
- xbFalse - Don't retrieve record.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::GetFirstKey( void *vpTag, xbInt16 iRetrieveSw ){
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- try{
- // clear out any history
- if( npTag->npNodeChain ){
- npTag->npNodeChain = FreeNodeChain( npTag->npNodeChain );
- npTag->npCurNode = NULL;
- }
- if(( iRc = ReadHeadBlock( 1 )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- // lRootBlock is now available
- if(( iRc = GetBlock( npTag, npTag->ulRootBlock, 1, (xbUInt32) npTag->iKeyItemLen )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- // if no keys on this node, and it's a leaf node then the index is empty
- xbUInt32 ulKeyPtr = eGetUInt32( npTag->npCurNode->cpBlockData );
- if( ulKeyPtr == 0 && IsLeaf( npTag, npTag->npCurNode )){
- iRc = XB_EMPTY;
- return iRc;
- }
- while( !IsLeaf( npTag, npTag->npCurNode )) // go down the chain looking for a leaf node
- {
- if(( iRc = GetKeyPtr( npTag, 0, npTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- if(( iRc = GetBlock( npTag, ulKeyPtr, 1, (xbUInt32) npTag->iKeyItemLen )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- }
- if( iRetrieveSw ){
- if(( iRc = GetDbfPtr( npTag, 0, npTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
- if(( iRc = dbf->GetRecord( ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
- }
- }
- catch( xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::GetFirstKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-/***********************************************************************/
-//! @brief Get the key expression for the given tag.
-/*!
- \param vpTag Tag to retrieve expression from.
- \returns Key expression.
-*/
-
-xbString &xbIxNdx::GetKeyExpression( const void * vpTag ) const{
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
- return npTag->sKeyExpression;
-}
-
-
-/***********************************************************************/
-//! @brief Get the key filter for the given tag.
-/*!
- NDX index files do not support filters. This returns NULL.
- \returns NULL.
-*/
-
-xbString &xbIxNdx::GetKeyFilter( const void * ) const{
- return sNullString;
-}
-/***********************************************************************/
-//! @brief Get the key length for the given tag.
-/*!
- \param vpTag Tag to retrieve key length for.
- \returns Length of key.
-*/
-xbInt32 xbIxNdx::GetKeyLen( const void * vpTag ) const{
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
- return npTag->iKeyLen;
-}
-/***********************************************************************/
-//! @brief Get child node number for given key number.
-/*!
- \param vpTag Tag to retrieve dbf rec number on.
- \param iKeyNo Key number for retrieval
- \param np Pointer to node
- \param ulKeyPtr Output node number
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::GetKeyPtr( void *vpTag, xbInt16 iKeyNo, xbIxNode *np, xbUInt32 &ulKeyPtr ) const {
-
- xbInt16 iRc = 0;
- xbInt16 iErrorStop = 0;
- try{
- #ifdef XB_DEBUG_SUPPORT
- // turn this off in production mode for better performance
- xbUInt32 ulNoOfKeys = eGetUInt32 ( np->cpBlockData );
- if( iKeyNo < 0 || iKeyNo > (xbInt16) ulNoOfKeys ){
- iErrorStop = 100;
- throw XB_INVALID_KEYNO;
- }
- #endif
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
- char *p = ( np->cpBlockData);
- p += (4 + (iKeyNo * npTag->iKeyItemLen));
- ulKeyPtr = eGetUInt32 ( p );
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::GetKeyPtr() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/***********************************************************************/
-//! @brief Returns key update status.
-/*!
- \param vpTag Tag to check status on.
- \returns XB_UPD_KEY Key updated.<br>
- XB_DEL_KEY Key deleted.<br>
- XB_ADD_KEY Key added.<br>
- 0 No key updates
-
-*/
-xbInt16 xbIxNdx::GetKeySts( void *vpTag ) const{
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
- return npTag->iKeySts;
-}
-/***********************************************************************/
-//! @brief Get character key type for given tag.
-/*!
- \param vpTag Tag to retrieve key type for.
- \returns Char key type.
-*/
-
-char xbIxNdx::GetKeyType( const void * vpTag ) const{
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
- return npTag->cKeyType;
-}
-
-/***********************************************************************/
-//! @brief Get numeric key type for given tag.
-/*!
- \param vpTag Tag to retrieve first key for.
- \returns Numeric key type.
-*/
-xbInt16 xbIxNdx::GetKeyTypeN( const void * vpTag ) const{
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
- return npTag->iKeyType;
-}
-/***********************************************************************/
-//! @brief Get the last key for the given tag.
-/*!
- \param vpTag Tag to retrieve last key on.
- \param iRetrieveSw xbTrue - Retrieve the record on success.<br>
- xbFalse - Don't retrieve record.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-xbInt16 xbIxNdx::GetLastKey( void *vpTag, xbInt16 iRetrieveSw ){
- return GetLastKey( 0, vpTag, iRetrieveSw );
-// return GetLastKey( 0, vpTag, 1 );
-
-}
-/***********************************************************************/
-//! @brief Get the last key for the given tag and starting node.
-/*!
- \param ulNodeNo Starting node
- \param vpTag Tag to retrieve last key on.
- \param iRetrieveSw xbTrue - Retrieve the record if key found.<br>
- xbFalse - Don't retrieve record.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-xbInt16 xbIxNdx::GetLastKey( xbUInt32 ulNodeNo, void *vpTag, xbInt16 iRetrieveSw ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbUInt32 ulKeyPtr = 0;
- xbUInt32 ulNoOfKeys = 0;
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- try{
- // clear out any history
- if( npTag->npNodeChain ){
- npTag->npNodeChain = FreeNodeChain( npTag->npNodeChain );
- npTag->npCurNode = NULL;
- }
- if( ulNodeNo == 0 ){
- if(( iRc = ReadHeadBlock( 1 )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- // lRootBlock is now available
- if(( iRc = GetBlock( npTag, npTag->ulRootBlock, 1, (xbUInt32) npTag->iKeyItemLen )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- } else {
- if(( iRc = GetBlock( npTag, ulNodeNo, 1, (xbUInt32) npTag->iKeyItemLen )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- }
- // if no keys on this node, then the index is empty
- ulNoOfKeys = eGetUInt32( npTag->npCurNode->cpBlockData );
- if( ulNoOfKeys == 0 && IsLeaf( npTag, npTag->npCurNode )){
- iRc = XB_EMPTY;
- return iRc;
- }
- npTag->npCurNode->iCurKeyNo = ulNoOfKeys;
- while( !IsLeaf( npTag, npTag->npCurNode ) ){ // go down the chain looking for a leaf node
- npTag->npCurNode->iCurKeyNo = eGetUInt32( npTag->npCurNode->cpBlockData );
- if(( iRc = GetKeyPtr( npTag, npTag->npCurNode->iCurKeyNo, npTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- if(( iRc = GetBlock( npTag, ulKeyPtr, 1, (xbUInt32) npTag->iKeyItemLen )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
- ulNoOfKeys = eGetUInt32( npTag->npCurNode->cpBlockData );
- npTag->npCurNode->iCurKeyNo = ulNoOfKeys;
- }
- // get here on a leaf node, it has one fewer iCurKeyNo
- npTag->npCurNode->iCurKeyNo--;
- if( iRetrieveSw ){
- ulNoOfKeys = eGetUInt32( npTag->npCurNode->cpBlockData );
- if(( iRc = GetDbfPtr( npTag, ulNoOfKeys - 1, npTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
- if(( iRc = dbf->GetRecord( ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 160;
- throw iRc;
- }
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::GetLastKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/***********************************************************************/
-//! @brief Get the last key for a block number.
-/*!
- \param vpTag Tag to retrieve first key on.
- \param ulBlockNo Block number for key retrieval.
- \param cpBuf output buffer for key placement
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::GetLastKeyForBlockNo( void *vpTag, xbUInt32 ulBlockNo, char *cpBuf ){
-
- // returns the last key for a given block number
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
-
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- try{
- xbIxNode * npSaveNodeChain = npTag->npNodeChain;
- xbIxNode * npSaveCurNode = npTag->npCurNode;
- npTag->npNodeChain = NULL;
-
- if(( iRc = GetLastKey( ulBlockNo, npTag, 0 )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- // set the key
- memcpy( cpBuf, GetKeyData( npTag->npCurNode, GetKeyCount( npTag->npCurNode ) - 1, npTag->iKeyItemLen ), (size_t) npTag->iKeyLen );
-
- // free memory
- npTag->npNodeChain = FreeNodeChain( npTag->npNodeChain );
- npTag->npNodeChain = npSaveNodeChain;
- npTag->npCurNode = npSaveCurNode;
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::GetLastKeyForBlockNo() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ) );
- }
- return iRc;
-}
-/***********************************************************************/
-//! @brief Get the next key for the given tag.
-/*!
- \param vpTag Tag to retrieve next key on.
- \param iRetrieveSw xbTrue - Retrieve the record on success.<br>
- xbFalse - Don't retrieve record.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::GetNextKey( void * vpTag, xbInt16 iRetrieveSw ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- try{
- if( !npTag->npNodeChain )
- return GetFirstKey( vpTag, iRetrieveSw );
-
- // more keys on this node? if yes, get the next one to the right
- xbUInt32 ulKeyPtr;
- if((eGetUInt32( npTag->npCurNode->cpBlockData ) -1) > npTag->npCurNode->iCurKeyNo ){
- npTag->npCurNode->iCurKeyNo++;
- if(( iRc = GetDbfPtr( npTag, npTag->npCurNode->iCurKeyNo, npTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- if( iRetrieveSw ){
- if(( iRc = dbf->GetRecord( ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- } else {
- return iRc;
- }
- } else {
- return iRc;
- }
- }
- // if at end of head node, then eof
- if( npTag->npCurNode->ulBlockNo == npTag->ulRootBlock )
- return XB_EOF;
-
- // This logic assumes that interior nodes have n+1 left node no's where n is he the number of keys in the node
- xbIxNode * TempIxNode = npTag->npCurNode;
- npTag->npCurNode = npTag->npCurNode->npPrev;
- TempIxNode = FreeNodeChain( TempIxNode );
-
- while( npTag->npCurNode->iCurKeyNo >= eGetUInt32( npTag->npCurNode->cpBlockData ) &&
- (npTag->npCurNode->ulBlockNo != npTag->ulRootBlock )){
- TempIxNode = npTag->npCurNode;
- npTag->npCurNode = npTag->npCurNode->npPrev;
- TempIxNode = FreeNodeChain( TempIxNode );
- }
-
- // head node and at end of head node, then eof
- if( npTag->npCurNode->ulBlockNo == npTag->ulRootBlock &&
- npTag->npCurNode->iCurKeyNo == eGetUInt32( npTag->npCurNode->cpBlockData ))
- return XB_EOF;
-
- // move one to the right
- npTag->npCurNode->iCurKeyNo++;
-
- if(( iRc = GetKeyPtr( npTag, npTag->npCurNode->iCurKeyNo, npTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
-
- if(( iRc = GetBlock( npTag, ulKeyPtr, 1, (xbUInt32) npTag->iKeyItemLen )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- while( !IsLeaf( npTag, npTag->npCurNode )) // go down the chain looking for a leaf node
- {
- if(( iRc = GetKeyPtr( npTag, 0, npTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
- if(( iRc = GetBlock( npTag, ulKeyPtr, 1, (xbUInt32) npTag->iKeyItemLen )) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
- }
- if( iRetrieveSw ){
- if(( iRc = GetDbfPtr( npTag, 0, npTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 160;
- throw iRc;
- }
- if(( iRc = dbf->GetRecord( ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 170;
- throw iRc;
- }
- }
- }
- catch( xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::GetNextKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-/***********************************************************************/
-//! @brief Get the previous key for the given tag.
-/*!
- \param vpTag Tag to retrieve previous key on.
- \param iRetrieveSw xbTrue - Retrieve the record on success.<br>
- xbFalse - Don't retrieve record.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-xbInt16 xbIxNdx::GetPrevKey( void * vpTag, xbInt16 iRetrieveSw ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- // This method assumes last index call landed on a valid key.
- // If last call resulted in an error, this method will returns XB_BOF
-
- try{
- if( !npTag->npNodeChain )
- return GetLastKey( 0, vpTag, iRetrieveSw );
-
- xbUInt32 ulKeyPtr;
- if( npTag->npCurNode->iCurKeyNo > 0 ){
- npTag->npCurNode->iCurKeyNo--;
-
- if(( iRc = GetDbfPtr( npTag, npTag->npCurNode->iCurKeyNo, npTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- if( iRetrieveSw ){
- if(( iRc = dbf->GetRecord( ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- } else {
- return iRc;
- }
- }
- }
-
- // next two lines might have been an issue
- if( npTag->npCurNode->ulBlockNo == npTag->ulRootBlock && GetKeyCount( npTag->npCurNode ) == 0 && IsLeaf( npTag, npTag->npCurNode ))
- return XB_EMPTY;
-
- if( npTag->npCurNode->ulBlockNo == npTag->ulRootBlock )
- return XB_BOF;
-
- // This logic assumes that interior nodes have n+1 left node no's where n is he the number of keys in the node
- xbIxNode * TempIxNode = npTag->npCurNode;
- npTag->npCurNode = npTag->npCurNode->npPrev;
- TempIxNode = FreeNodeChain( TempIxNode );
-
- while( npTag->npCurNode->iCurKeyNo == 0 &&
- (npTag->npCurNode->ulBlockNo != npTag->ulRootBlock )){
- TempIxNode = npTag->npCurNode;
- npTag->npCurNode = npTag->npCurNode->npPrev;
- TempIxNode = FreeNodeChain( TempIxNode );
- }
-
- // head node and at end of head node, then bof
- if( npTag->npCurNode->ulBlockNo == npTag->ulRootBlock &&
- npTag->npCurNode->iCurKeyNo == 0 )
- return XB_BOF;
-
- // move one to the left
- npTag->npCurNode->iCurKeyNo--;
-
- if(( iRc = GetKeyPtr( npTag, npTag->npCurNode->iCurKeyNo, npTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
-
- if(( iRc = GetBlock( npTag, ulKeyPtr, 1, (xbUInt32) npTag->iKeyItemLen )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
-
- while( !IsLeaf( npTag, npTag->npCurNode )){ // go down the chain looking for a leaf node
- npTag->npCurNode->iCurKeyNo = eGetUInt32( npTag->npCurNode->cpBlockData );
- if(( iRc = GetKeyPtr( npTag, npTag->npCurNode->iCurKeyNo, npTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
- if(( iRc = GetBlock( npTag, ulKeyPtr, 1, (xbUInt32) npTag->iKeyItemLen )) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
- }
-
- npTag->npCurNode->iCurKeyNo = eGetUInt32( npTag->npCurNode->cpBlockData ) - 1;
- if( iRetrieveSw ){
- if(( iRc = GetDbfPtr( npTag, npTag->npCurNode->iCurKeyNo, npTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 160;
- throw iRc;
- }
- if(( iRc = dbf->GetRecord( ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 170;
- throw iRc;
- }
- }
- }
-
- catch( xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::GetPrevKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-/***********************************************************************/
-//! @brief Get the sort order for given tag.
-/*!
- Ndx indices only support ascending keys.
- \returns 0
-*/
-xbBool xbIxNdx::GetSortOrder( void * ) const{
- return 0;
-}
-/***********************************************************************/
-//! @brief Get tag for tag number.
-/*!
- \returns Pointer to ndx tag.
-*/
-void * xbIxNdx::GetTag( xbInt16 ) const{
- return ndxTag;
-}
-/***********************************************************************/
-//! @brief Get tag for tag name.
-/*!
- \returns Pointer to ndx tag.
-*/
-void * xbIxNdx::GetTag( xbString & ) const{
- return ndxTag;
-}
-
-/***********************************************************************/
-//! @brief Get tag count.
-/*!
- NDX index files contain one tag.
- \returns 1
-*/
-
-xbInt16 xbIxNdx::GetTagCount() const{
- return 1;
-}
-/***********************************************************************/
-//! @brief Get tag name.
-/*!
- \returns Tag name.
-*/
-xbString &xbIxNdx::GetTagName( void * ) const {
-// char * xbIxNdx::GetTagName( void * ) const {
-
- return ndxTag->sTagName;
-
-}
-/***********************************************************************/
-//! @brief Get tag name.
-/*!
- \returns Tag name.
-*/
-const char * xbIxNdx::GetTagName( void *, xbInt16 ) const {
- return ndxTag->sTagName;
-}
-
-/***********************************************************************/
-//! @brief Get the unique setting for given tag.
-/*!
- \param vpTag Tag to unique setting on.
- \returns xbTrue - Unique index.<br> xbFalse - Not unique index.
-*/
-xbBool xbIxNdx::GetUnique( void * vpTag ) const{
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
- return npTag->iUnique;
-}
-
-/***********************************************************************/
-//! @brief Insert key into interior node.
-/*!
- Insert key into non-full interior node.<br>
- Assumes valid inputs
-
- \param vpTag Tag in play.
- \param npNode Node for insertion.
- \param iSlotNo Slot number to insert key.
- \param ulPtr Pointer number to insert.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::InsertNodeI( void *vpTag, xbIxNode *npNode, xbInt16 iSlotNo, xbUInt32 ulPtr ){
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- char *pTrg;
- xbInt16 iSrcPos;
- char *pLastKey = NULL;
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- try{
- // update number of keys on the node
- xbInt32 lKeyCnt = GetKeyCount( npNode );
- iSrcPos = 12 + (iSlotNo * npTag->iKeyItemLen);
-
- char *pSrc = npNode->cpBlockData;
- pSrc += iSrcPos;
-
- // if not appending to the end of the node, make some room, move things to the right
- if( iSlotNo < lKeyCnt ) {
- xbInt16 iCopyLen = ((lKeyCnt - iSlotNo) * npTag->iKeyItemLen) - 4;
- pTrg = pSrc;
- pTrg += npTag->iKeyItemLen;
- memmove( pTrg, pSrc, (size_t) iCopyLen );
- }
-
- // get the right most key for the left part of the split node
- xbUInt32 ulKeyPtr2;
- if(( iRc = GetKeyPtr( vpTag, npNode->iCurKeyNo, npNode, ulKeyPtr2 )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- // get the new right key value for the freshly split node
- pLastKey = (char *) malloc((size_t) ndxTag->iKeyLen);
- if(( iRc = GetLastKeyForBlockNo( vpTag, ulKeyPtr2, pLastKey )) != XB_NO_ERROR ){
- iRc = 110;
- throw iRc;
- }
- // write the key value
- pTrg = pSrc;
- char *pTrg2 = pSrc;
- pSrc = pLastKey;
- for( xbInt16 i = 0; i < npTag->iKeyLen; i++ )
- *pTrg++ = *pSrc++;
-
- pTrg2 += (npTag->iKeyItemLen - 8);
- ePutUInt32( pTrg2, ulPtr );
- ePutInt32( npNode->cpBlockData, ++lKeyCnt );
-
- // write out the updated block to disk
- if(( iRc = WriteBlock( npNode->ulBlockNo, GetBlockSize(), npNode->cpBlockData )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- if( pLastKey )
- free( pLastKey );
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::InsertNodeI() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- if( pLastKey )
- free( pLastKey );
- }
- return iRc;
-}
-/***********************************************************************/
-//! @brief Insert key into leaf node.
-/*!
- Insert key into non-full leaf node.<br>
- Assumes valid inputs
-
- \param vpTag Tag in play.
- \param npNode Node for insertion.
- \param iSlotNo Slot number to insert key.
- \param ulPtr Pointer number to insert.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-xbInt16 xbIxNdx::InsertNodeL( void *vpTag, xbIxNode *npNode, xbInt16 iSlotNo,
- char * cpKeyBuf, xbUInt32 ulPtr ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- char *pSrc;
- char *pTrg;
- char *pKeyPos;
- xbString sMsg;
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- try{
- xbInt32 lKeyCnt = GetKeyCount( npNode );
- xbInt16 iKeyPos = 4 + iSlotNo * npTag->iKeyItemLen;
- pKeyPos = npNode->cpBlockData;
- pKeyPos += iKeyPos;
-
- // if not appending to end, make space, move things right
- if( iSlotNo < lKeyCnt ) {
- xbInt16 iCopyLen = (lKeyCnt - iSlotNo) * npTag->iKeyItemLen;
- pTrg = pKeyPos;
- pTrg += npTag->iKeyItemLen;
- memmove( pTrg, pKeyPos, (size_t) iCopyLen );
- }
- // if leaf, write rec number
- pTrg = pKeyPos;
- memset( pTrg, 0x00, 4 );
- pTrg += 4;
- ePutUInt32( pTrg, ulPtr );
- pTrg += 4;
-
- // write the key value
- pSrc = cpKeyBuf;
- for( xbInt16 i = 0; i < npTag->iKeyLen; i++ )
- *pTrg++ = *pSrc++;
-
- // update number of keys on the node
- ePutInt32( npNode->cpBlockData, ++lKeyCnt );
-
- // write out the updated block to disk
- if(( iRc = WriteBlock( npNode->ulBlockNo, GetBlockSize(), npNode->cpBlockData )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::InsertNodeL() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-/***********************************************************************/
-//! @brief Determine node leaf status
-/*!
- \param npNode Node to examine.
- \returns xbTrue - Leaf node.<br> xbFalse - Interior node.
-*/
-xbBool xbIxNdx::IsLeaf( void *, xbIxNode *npNode ) const {
- xbUInt32 ulBlock = eGetUInt32 ( npNode->cpBlockData+4 );
- if( ulBlock > 0 ) // if the second four bytes are a number, it's an interior node
- return false;
- else
- return true;
-}
-/***********************************************************************/
-//! @brief Determine if key exists.
-/*!
- This method assumes the key has already been built and is in either
- cpKeyBuf or dKey.
-
- \param vpTag - Pointer to tag.
- \returns xbTrue - Key exists.<br> xbFalse - Key does not exist.
-*/
-xbInt16 xbIxNdx::KeyExists( void * vpTag ){
-
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- xbInt16 iRc = FindKey( vpTag, npTag->cpKeyBuf, npTag->iKeyLen, 0 );
- if( iRc == 0 )
- return 1;
- else
- return 0;
-}
-
-/***********************************************************************/
-//! @brief Set position for key add.
-/*!
- This routine is called by the AddKey() method and is used to position
- the node chain to the position the new key should be added to the index.
-
- \param npTag Pointer to npTag.
- \param ulAddRecNo Record number to add.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-xbInt16 xbIxNdx::KeySetPosAdd( xbNdxTag *npTag, xbUInt32 ulAddRecNo ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- try{
-
- iRc = FindKey( npTag, npTag->cpKeyBuf, npTag->iKeyLen, 0 );
- if( iRc == XB_NOT_FOUND || iRc == XB_EMPTY )
- return XB_NO_ERROR; // good position
-
- else if( iRc != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- // get here if key was found, get the right most instance of any non unique key for append, find correct spot for update
- if( GetUnique() == 0 ){
- xbUInt32 ulCurRecNo;
- if(( iRc = GetDbfPtr( npTag, npTag->npCurNode->iCurKeyNo, npTag->npCurNode, ulCurRecNo )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- xbBool bKeysMatch = xbTrue;
- while( bKeysMatch && ulAddRecNo > ulCurRecNo && iRc == XB_NO_ERROR ){
- if(( iRc = GetNextKey( npTag, 0 )) == XB_NO_ERROR ){
- if( memcmp( GetKeyData( npTag->npCurNode, npTag->npCurNode->iCurKeyNo, npTag->iKeyItemLen ), npTag->cpKeyBuf, (size_t) npTag->iKeyLen ))
- bKeysMatch = xbFalse;
- else{
- if(( iRc = GetDbfPtr( npTag, npTag->npCurNode->iCurKeyNo, npTag->npCurNode, ulCurRecNo )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- }
- }
- }
- }
- if( iRc == XB_EOF ){ // eof condition
- if(( iRc = GetLastKey( 0, npTag, 0 )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- npTag->npCurNode->iCurKeyNo++;
- return XB_NO_ERROR;
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::KeySetPos() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/***********************************************************************/
-//! @brief Set position for key add.
-/*!
- This routine is called by the DeleteKey() method and is used to position
- the node chain to the position the old key should be deleted from the index.
-
- \param npTag Pointer to npTag.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::KeySetPosDel( xbNdxTag *npTag ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbString sMsg;
-
- try{
- iRc = FindKey( NULL, npTag->cpKeyBuf2, npTag->iKeyLen, 0 );
- if( iRc == XB_NOT_FOUND || iRc == XB_EMPTY )
- return XB_NO_ERROR; // good position
- else if( iRc != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- xbUInt32 ulIxRecNo;
- if(( iRc = GetDbfPtr( npTag, npTag->npCurNode->iCurKeyNo, npTag->npCurNode, ulIxRecNo )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- if( ulIxRecNo == dbf->GetCurRecNo())
- return XB_NO_ERROR;
- if( GetUnique() == 1 ){
- iErrorStop = 120;
- iRc = XB_NOT_FOUND;
- throw iRc;
- }
- xbBool bFound = xbFalse;
- xbBool bKeysMatch = xbTrue;
- while( bKeysMatch && !bFound && iRc == XB_NO_ERROR ){
- if(( iRc = GetNextKey( npTag, 0 )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- if( memcmp( GetKeyData( npTag->npCurNode, npTag->npCurNode->iCurKeyNo, npTag->iKeyItemLen ), npTag->cpKeyBuf2, (size_t) npTag->iKeyLen )){
- bKeysMatch = xbFalse;
- } else {
- if(( iRc = GetDbfPtr( npTag, npTag->npCurNode->iCurKeyNo, npTag->npCurNode, ulIxRecNo )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
- if( ulIxRecNo == dbf->GetCurRecNo())
- bFound = xbTrue;
- }
- }
- if( bFound )
- return XB_NO_ERROR;
- else
- return XB_NOT_FOUND;
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::KeySetPosDel() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-/***********************************************************************/
-//! @brief Returns key filter status.
-/*!
- \param vpTag Tag to check status on.
- \returns xbtrue - Key was updated.<br>xbFalse - Key not updated.
-
- Always true for NDX style indices.
-*/
-//inline xbBool xbIxNdx::KeyFiltered( void *vpTag ) const{
-// return xbTrue;
-//}
-
-/***********************************************************************/
-//! @brief Read head block of index file.
-/*!
- \param iOpt 0 - Read in entire block
- 1 - Read in only dynamic section of block
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-xbInt16 xbIxNdx::ReadHeadBlock( xbInt16 iOpt = 0 ) {
-
- xbInt16 iRc = 0;
- xbInt16 iErrorStop = 0;
- try{
- if( !FileIsOpen()){
- iRc = XB_NOT_OPEN;
- iErrorStop = 100;
- throw iRc;
- }
- xbInt16 iLen;
- iOpt == 0 ? iLen = 512 : iLen = 21;
-
- if(( iRc = ReadBlock( (xbUInt32) 0, (size_t) iLen, cNodeBuf )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- char *p = cNodeBuf;
- ndxTag->ulRootBlock = eGetUInt32( p ); p+=4;
- ndxTag->ulTotalBlocks = eGetUInt32( p ); p+=5;
- if( iOpt == 0 ){
- ndxTag->cKeyType = *p; p+=3;
- ndxTag->iKeyLen = eGetInt16( p ); p+=2;
- ndxTag->iKeysPerBlock = eGetInt16( p ); p+=2;
- ndxTag->iKeyType = eGetInt16( p ); p+=2;
- ndxTag->iKeyItemLen = eGetInt16( p ); p+=2;
- ndxTag->cSerNo = *p; p+=3;
- ndxTag->iUnique = *p; p++;
- ndxTag->sKeyExpression.Set( p );
-
- if( ndxTag->exp )
- delete ndxTag->exp;
-
- ndxTag->exp = new xbExp( xbase, dbf );
- if(( iRc = ndxTag->exp->ParseExpression( ndxTag->sKeyExpression.Str() )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
-
- if( ndxTag->cpKeyBuf )
- free( ndxTag->cpKeyBuf );
- if( ndxTag->cpKeyBuf2 )
- free( ndxTag->cpKeyBuf2 );
-
- ndxTag->cpKeyBuf = (char *) malloc( (size_t) ndxTag->iKeyLen );
- ndxTag->cpKeyBuf2 = (char *) malloc( (size_t) ndxTag->iKeyLen );
-
- if( ndxTag->sTagName == "" )
- GetFileNamePart( ndxTag->sTagName );
-
- } else {
- p+= 11;
- ndxTag->cSerNo = *p;
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::ReadHeadBlock() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/***********************************************************************/
-//! @brief Reindex a tag.
-/*!
- \param vpTag Pointer to tag pointer.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::Reindex( void **vpTag ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- //xbNdxTag * npTag;
- //vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- try{
- xbString sFileName = GetFqFileName();
- xbString sKey; // = GetKeyExpression( vpTag );
- sKey.Set( GetKeyExpression( *vpTag ));
- xbInt16 iUnique = GetUnique( *vpTag );
- xbString sFilter = "";
-
- void *vpTag2;
- if(( iRc = CreateTag( sFileName, sKey, sFilter, 0, iUnique, xbTrue, &vpTag2 )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
-
- xbUInt32 ulRecCnt = 0;
- if(( iRc = dbf->GetRecordCnt( ulRecCnt )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
-
- for( xbUInt32 l = 1; l <= ulRecCnt; l++ ){
- if(( iRc = dbf->GetRecord( l )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
-
- if(( iRc = CreateKey( vpTag2, 1 )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
-
- if( iUnique ){
- iRc = CheckForDupKey( vpTag2 );
- if( iRc != 0 ){
- if( iRc < 0 ){
- iErrorStop = 140;
- throw iRc;
- }
- return XB_KEY_NOT_UNIQUE;
- }
- }
-
- if(( iRc = AddKey( vpTag2, l )) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
- }
- *vpTag = vpTag2;
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::Reindex() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-/***********************************************************************/
-//! @brief Set current tag.
-/*!
- For ndx indices, there is only one tag.
- \returns XB_NO_ERROR.
-*/
-xbInt16 xbIxNdx::SetCurTag( xbInt16 ) {
- xbIx::SetCurTag( ndxTag );
- return XB_NO_ERROR;
-}
-/***********************************************************************/
-//! @brief Set current tag.
-/*!
- For ndx indices, there is only one tag.
- \returns XB_NO_ERROR.
-*/
-xbInt16 xbIxNdx::SetCurTag( xbString & ) {
- xbIx::SetCurTag( ndxTag );
- dbf->SetCurTag( "NDX", this, GetTag(0) );
- return XB_NO_ERROR;
-}
-
-/***********************************************************************/
-//! @brief Split an interior node
-/*!
-
- This routine splits an interior node into two nodes, divided by dSplitFactor.<br>
- This behaves differently than V7 Dbase. V7 does not balance the nodes.<br>
- For V7, if adding a key to the end of a node, it will create a right node
- with only one key, and the left node is still full.<br><br>
-
- Possible performance improvement options.<br>
- Two modes when splitting:<br>
- a) Split nodes in the middle - good for random access applications<br>
- b) Split off right node with only one key - good for applications with
- expectation of ascending keys added moving forward.<br>
-
- This routine first inserts the key into the left node in the appropriate location
- then splits the node based on the split factor setting.
-
- \param vpTag Tag in play.
- \param npLeft Left node to split.
- \param npRight Right node to split.
- \param iSlotNo Slot number for split.
- \param ulPtr Pointer number to insert.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::SplitNodeI( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight, xbInt16 iSlotNo, xbUInt32 ulPtr ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbNdxTag * npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
- xbDouble dSplitFactor = .5; // split the nodes 50/50
- xbString sMsg;
-
- try{
- xbInt32 lKeyCnt = GetKeyCount( npLeft );
- xbInt32 lNewLeftKeyCnt = (xbInt32) ((lKeyCnt + 1) * dSplitFactor) + 1;
- xbInt32 lNewRightKeyCnt = lKeyCnt - lNewLeftKeyCnt;
- xbInt16 iSrcPos;
- xbInt16 iCopyLen;
- char *pSrc;
- char *pTrg;
-
- // insert the key into the left node
- if(( iRc = InsertNodeI( vpTag, npLeft, iSlotNo, ulPtr )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
-
- // move the right half of the left node to the right node
- iSrcPos = ((lNewLeftKeyCnt + 1) * npTag->iKeyItemLen) + 4;
- iCopyLen = (lNewRightKeyCnt * npTag->iKeyItemLen) + 4;
- pSrc = npLeft->cpBlockData;
- pSrc += iSrcPos;
- pTrg = npRight->cpBlockData;
- pTrg += 4;
- memmove( pTrg, pSrc, (size_t) iCopyLen );
-
- // write the new key counts into the nodes
- pTrg = npLeft->cpBlockData;
- ePutInt32( pTrg, lNewLeftKeyCnt );
- pTrg = npRight->cpBlockData;
- ePutInt32( pTrg, lNewRightKeyCnt );
-
- // write the new key counts into the nodes
- pTrg = npLeft->cpBlockData;
- ePutInt32( pTrg, lNewLeftKeyCnt );
- pTrg = npRight->cpBlockData;
- ePutInt32( pTrg, lNewRightKeyCnt );
-
- // write out the block
- if(( iRc = WriteBlock( npLeft->ulBlockNo, GetBlockSize(), npLeft->cpBlockData )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- // write out the block
- if(( iRc = WriteBlock( npRight->ulBlockNo, GetBlockSize(), npRight->cpBlockData )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::SplitNodeI() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/***********************************************************************/
-//! @brief Split a leaf node.
-/*!
- This routine splits an index leaf into two nodes, divided by dSplitFactor.<br>
- This behaves differently than V7 Dbase. V7 does not balance the nodes.<br>
- For V7, if adding a key to the end of a node, it will create a right node
- with only one key, and the left node is still full.<br><br>
-
- Possible performance improvement options.<br>
- Two modes when splitting:<br>
- a) Split nodes in the middle - good for random access applications<br>
- b) Split off right node with only one key - good for applications with
- expectation of ascending keys added moving forward.<br>
-
- This routine first inserts the key into the left node in the appropriate location
- then splits the node based on the split factor setting.
-
- \param vpTag Tag in play.
- \param npLeft Left node to split.
- \param npRight Right node to split.
- \param iSlotNo Slot number for split.
- \param ulPtr Pointer number to insert.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::SplitNodeL( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight,
- xbInt16 iSlotNo, char * cpKeyBuf, xbUInt32 ulPtr ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbDouble dSplitFactor = .5;
- xbNdxTag *npTag;
- vpTag ? npTag = (xbNdxTag *) vpTag : npTag = ndxTag;
-
- xbString sMsg;
- try{
- xbInt32 lKeyCnt = GetKeyCount( npLeft );
- xbInt32 lNewLeftKeyCnt = (xbInt32) ((lKeyCnt + 1) * dSplitFactor) + 1;
- xbInt32 lNewRightKeyCnt = lKeyCnt + 1 - lNewLeftKeyCnt;
-
- // xbInt16 iSrcPos;
- xbInt16 iLen;
- char *pSrc = npLeft->cpBlockData;
- char *pTrg;
-
- if(( iRc = InsertNodeL( vpTag, npLeft, iSlotNo, cpKeyBuf, ulPtr )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
-
- // move right half off of left node to the right node
- pSrc = npLeft->cpBlockData;
- pSrc += ((lNewLeftKeyCnt * npTag->iKeyItemLen)+4);
- pTrg = npRight->cpBlockData;
- pTrg += 4;
- iLen = lNewRightKeyCnt * npTag->iKeyItemLen;
- memmove( pTrg, pSrc, (size_t) iLen );
-
- // write the new key counts into the nodes
- pTrg = npLeft->cpBlockData;
- ePutInt32( pTrg, lNewLeftKeyCnt );
- pTrg = npRight->cpBlockData;
- ePutInt32( pTrg, lNewRightKeyCnt );
-
- // write out the left block
- if(( iRc = WriteBlock( npLeft->ulBlockNo, GetBlockSize(), npLeft->cpBlockData )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- // write out the right block
- if(( iRc = WriteBlock( npRight->ulBlockNo, GetBlockSize(), npRight->cpBlockData )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::SplitNodeL() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/***********************************************************************/
-//! @brief UpdateTagKey
-/*!
- This routine updates a key or a given tag.
- The file header is considered to be the first 2048 bytes in the file.
-
- \param cAction A - Add a key.<br>
- D - Delete a key.<br>
- R - Revise a key.<br>
- \param vpTg - Pointer to tag.<br>
- \param ulRecNo - Record number association with the action.<br>
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxNdx::UpdateTagKey( char cAction, void *vpTag, xbUInt32 ulRecNo ){
-
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- // ..xbNdxTag *npTag = (xbMdxTag *) vpTag;
-
- try{
- // save off any needed fileds for updating
- // xbUInt32 ulTagSizeSave = mpTag->ulTagSize;
- //xbUInt32 ulLeftChildSave = mpTag->ulLeftChild;
- //xbUInt32 ulRightChildSave = mpTag->ulRightChild;
-
-
- if( cAction == 'D' || cAction == 'R' ){
-// std::cout << "UpdateTagKey delete\n";
- if(( iRc = DeleteKey( vpTag )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- }
-
- if( cAction == 'A' || cAction == 'R' ){
- if(( iRc = AddKey( vpTag, ulRecNo )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- }
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::UpdateTagKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-/***********************************************************************/
-//! @brief Write head block.
-/*!
- Commit the index head node to disk.
- \param iOpt 0 - Entire header.<br>
- 1 - Update root block, number of blocks and seq number.<br>
- 2 - Update sequence number only<br>
- \returns <a href="xbretcod_8h.html">
-*/
-
-xbInt16 xbIxNdx::WriteHeadBlock( xbInt16 iOpt ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
-
- try{
- if( iOpt == 2 ){
-
- // increment the serial number
- if( ndxTag->cSerNo >= 0 && ndxTag->cSerNo < 127 )
- ndxTag->cSerNo++;
- else
- ndxTag->cSerNo = 0;
-
- if(( iRc = xbFseek( 20, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- if(( iRc = xbFputc( ndxTag->cSerNo )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- } else if( iOpt == 1 ){
- xbRewind();
- char buf[8];
- ePutUInt32( &buf[0], ndxTag->ulRootBlock );
- ePutUInt32( &buf[4], ndxTag->ulTotalBlocks );
- if(( iRc = xbFwrite( buf, 8, 1 )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- return WriteHeadBlock( 2 );
-
- } else if ( iOpt == 0 ){
-
- char buf[512];
- memset( buf, 0x00, 512 );
- ePutUInt32( &buf[0], ndxTag->ulRootBlock );
- ePutUInt32( &buf[4], ndxTag->ulTotalBlocks );
- buf[9] = ndxTag->cKeyType;
- buf[11] = 0x1B;
- ePutInt16( &buf[12], ndxTag->iKeyLen );
- ePutInt16( &buf[14], ndxTag->iKeysPerBlock );
- ePutInt16( &buf[16], ndxTag->iKeyType );
- ePutInt16( &buf[18], ndxTag->iKeyItemLen );
- if( ndxTag-> iUnique ) buf[23] = 0x01;
-
- for( xbUInt32 i = 0; i < ndxTag->sKeyExpression.Len(); i++ )
- buf[i+24] = ndxTag->sKeyExpression.GetCharacter(i+1);
-
- xbRewind();
- if(( iRc = xbFwrite( buf, 512, 1 )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- } else {
- iRc = XB_INVALID_OPTION;
- throw iRc;
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxNdx::WriteHeadBlock() Exception Caught. Error Stop = [%d] iRc = [%d] option = [%d] ser=[%d]", iErrorStop, iRc, iOpt, ndxTag->cSerNo );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-/***********************************************************************/
-} /* namespace */
-#endif /* XB_NDX_SUPPORT */
-
-
-