summaryrefslogtreecommitdiff
path: root/src/core/xbixmdx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/xbixmdx.cpp')
-rwxr-xr-xsrc/core/xbixmdx.cpp5073
1 files changed, 0 insertions, 5073 deletions
diff --git a/src/core/xbixmdx.cpp b/src/core/xbixmdx.cpp
deleted file mode 100755
index 135cde8..0000000
--- a/src/core/xbixmdx.cpp
+++ /dev/null
@@ -1,5073 +0,0 @@
-/* xbixmdx.cpp
-
-XBase64 Software Library
-
-Copyright (c) 1997,2003,2014,2022,2023 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
-
-
- MDX indices are comprised of blocks and pages.
- A page is 512 bytes.
- A Block is one or more pages.
- The default block size is two 512 byte pages per block.
- Nodes are used for storing block images in memory
-
-*/
-
-#include "xbase.h"
-
-#ifdef XB_MDX_SUPPORT
-
-namespace xb{
-
-/***********************************************************************/
-xbIxMdx::xbIxMdx( xbDbf *dbf ) : xbIx( dbf ){
- Init();
-}
-/***********************************************************************/
-//void xbIxMdx::Init( xbInt16 iOpt ){
-void xbIxMdx::Init( xbInt16 ){
-
- cVersion = 0;
- cCreateYY = 0;
- cCreateMM = 0;
- cCreateDD = 0;
- sFileName = "";
- iBlockFactor = 0;
- cProdIxFlag = 0;
- cTagEntryCnt = 0;
- iTagLen = 0;
- iTagUseCnt = 0;
- cNextTag = 0;
- c1B = 0x0b;
- ulPageCnt = 0;
- ulFirstFreePage = 0;
- ulNoOfBlockAvail = 0;
- cUpdateYY = 0;
- cUpdateMM = 0;
- cUpdateDD = 0;
- mdxTagTbl = NULL;
- cNodeBuf = NULL;
- bReuseEmptyNodes = xbTrue;
-}
-/***********************************************************************/
-xbIxMdx::~xbIxMdx(){
- if( cNodeBuf )
- free( cNodeBuf );
-
- if( FileIsOpen())
- Close();
-}
-/***********************************************************************/
-//! @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 xbIxMdx::AddKey( void * vpTag, xbUInt32 ulRecNo ){
-
- xbMdxTag * npTag = (xbMdxTag *) vpTag;
- if( GetUniqueKeyOpt() == XB_EMULATE_DBASE && npTag->bFoundSts )
- return XB_NO_ERROR;
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbInt16 iHeadNodeUpdateOpt = 2;
- xbIxNode * npRightNode = NULL;
- xbUInt32 ulNewRightChild = 0;
-
- try{
- if(( iRc = xbIxMdx::KeySetPosAdd( npTag, ulRecNo )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
-
- xbInt32 lKeyCnt = GetKeyCount( npTag->npCurNode );
-
- // std::cout << "xbIxMdx::AddKeys() lKeyCnt = " << lKeyCnt << " KeysPerBlock = " << npTag->iKeysPerBlock << " npBlockNo = " << npTag->npCurNode->ulBlockNo << "\n";
-
- if( lKeyCnt < npTag->iKeysPerBlock ){
- // Section A - add key to appropriate position if space available
- // std::cout << "AddKey Section A begin\n";
- if(( iRc = InsertNodeL( npTag, npTag->npCurNode, npTag->npCurNode->iCurKeyNo, npTag->cpKeyBuf, ulRecNo )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- //std::cout << "AddKey Section A end\n";
- } else {
-
- // land here with a full leaf node
- // std::cout << "Section B begin split leaf node\n";
-
- iHeadNodeUpdateOpt = 1;
- npRightNode = AllocateIxNode( npTag, GetBlockSize() + (xbUInt32) npTag->iKeyItemLen, npTag->npCurNode->ulBlockNo * (xbUInt32) iBlockFactor );
- if( !npRightNode ){
- iErrorStop = 120;
- iRc = XB_NO_MEMORY;
- throw iRc;
- }
-
- if(( npTag->npCurNode->ulBlockNo * (xbUInt32) iBlockFactor ) == npTag->ulRightChild ){
- ulNewRightChild = npRightNode->ulBlockNo * (xbUInt32) iBlockFactor;
- }
-
- // std::cout << "ulNewRightChild = " << ulNewRightChild << "\n";
-
- if(( iRc = xbIxMdx::SplitNodeL( npTag, npTag->npCurNode, npRightNode, npTag->npCurNode->iCurKeyNo, npTag->cpKeyBuf, ulRecNo )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- xbUInt32 ulTempBlockNo = npRightNode->ulBlockNo;
-
-
- //std::cout << "ulTempBlockNo = " << ulTempBlockNo << "\n";
- //std::cout << "key count left block " << GetKeyCount( npTag->npCurNode ) << "\n";
- //std::cout << "key count right block " << GetKeyCount( npRightNode ) << "\n";
-
-
- //std::cout << "Section B end\n";
-
- // section C - go up the tree, splitting nodes as necessary
- xbIxNode * npParent = npTag->npCurNode->npPrev;
-
-
- while( npParent && GetKeyCount( npParent ) >= npTag->iKeysPerBlock ){
- //std::cout << "Section C begin interior node is full\n";
- npRightNode = FreeNodeChain( npRightNode );
- npRightNode = AllocateIxNode( npTag, GetBlockSize() + (xbUInt32) npTag->iKeyItemLen, npParent->ulBlockNo * (xbUInt32) iBlockFactor );
- //std::cout << "Section C - B new right node block number for interior node split= " << npRightNode->ulBlockNo << "\n";
-
- if( !npRightNode ){
- iErrorStop = 140;
- iRc = XB_NO_MEMORY;
- throw iRc;
- }
- //std::cout << "Section C - going to split interior node C\n";
-
- if(( iRc = SplitNodeI( npTag, npParent, npRightNode, npParent->iCurKeyNo, BlockToPage( ulTempBlockNo ))) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
- // std::cout << "Section C - interior node split \n";
- ulTempBlockNo = npRightNode->ulBlockNo;
- npTag->npCurNode = npParent;
- npParent = npParent->npPrev;
- }
-
- // std::cout << "Past Section C Cur Node Block No = " << npTag->npCurNode->ulBlockNo << " root page = " << npTag->ulRootPage << "\n";
- // section D - if cur node is split root, create new root
-
- if(( npTag->npCurNode->ulBlockNo * (xbUInt32) iBlockFactor ) == npTag->ulRootPage ){
-
- // std::cout << "Section D begin right node = " << npRightNode << "\n";
-
- if(( iRc = AddKeyNewRoot( npTag, npTag->npCurNode, npRightNode )) != XB_NO_ERROR ){
- iErrorStop = 160;
- throw iRc;
- }
-
- if( npRightNode )
- npRightNode = FreeNodeChain( npRightNode );
-
- // std::cout << "Section D end\n";
-
- } else {
-
- // std::cout << "Section E, put key in parent\n";
- if(( iRc = InsertNodeI( (void *) vpTag, (xbIxNode *) npParent, (xbInt16) npParent->iCurKeyNo, BlockToPage( npRightNode->ulBlockNo ))) != XB_NO_ERROR ){
- iErrorStop = 170;
- throw iRc;
- }
- }
- }
-
- // update the header
- if(( iRc = WriteHeadBlock( iHeadNodeUpdateOpt )) != XB_NO_ERROR ){
- iErrorStop = 180;
- throw iRc;
- }
-
- // if adding the first key, set the cHasKeys field
- if( !npTag->cHasKeys ){
- npTag->cHasKeys = 0x01;
- if(( iRc = xbFseek( ((npTag->ulTagHdrPageNo * 512) + 246), SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 190;
- throw iRc;
- }
- if(( iRc = xbFwrite( &npTag->cHasKeys, 1, 1 )) != XB_NO_ERROR ){
- iErrorStop = 200;
- throw iRc;
- }
- }
-
- if( ulNewRightChild > 0 ){
-
-// std::cout << "ulRightChild was = " << npTag->ulRightChild << " changed to " << ulNewRightChild << "\n";
-
- char cBuf[4];
- ePutUInt32( cBuf, ulNewRightChild );
- if(( iRc = xbFseek( ((npTag->ulTagHdrPageNo * 512) + 252), SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 210;
- throw iRc;
- }
- if(( iRc = xbFwrite( &cBuf, 4, 1 )) != XB_NO_ERROR ){
- iErrorStop = 220;
- throw iRc;
- }
-// std::cout << "setting right child\n";
- npTag->ulRightChild = ulNewRightChild;
- }
-
- if( npRightNode )
- npRightNode = FreeNodeChain( npRightNode );
- npTag->npNodeChain = FreeNodeChain( npTag->npNodeChain );
- npTag->npCurNode = NULL;
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::AddKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/***********************************************************************/
-void xbIxMdx::AppendNodeChain( void *vpTag, xbIxNode * npNode ){
- xbMdxTag * mdxTag = (xbMdxTag *) vpTag;
- if( mdxTag->npNodeChain == NULL ){
- mdxTag->npNodeChain = npNode;
- mdxTag->npCurNode = npNode;
- } else {
- npNode->npPrev = mdxTag->npCurNode;
- mdxTag->npCurNode->npNext = npNode;
- mdxTag->npCurNode = npNode;
- }
- // time stamp the node chain
- GetFileMtime( mdxTag->tNodeChainTs );
-}
-
-/***********************************************************************/
-//! @brief Add new root node.
-/*!
- \param mpTag Tag to update.
- \param npLeft Left node.
- \param npRight Right node.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-xbInt16 xbIxMdx::AddKeyNewRoot( xbMdxTag *npTag, xbIxNode *npLeft, xbIxNode *npRight ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- char *pLastKey = NULL;
-
- try{
- xbIxNode *npRoot = AllocateIxNode( npTag, GetBlockSize() + (xbUInt32) npTag->iKeyItemLen, npRight->ulBlockNo * (xbUInt32) iBlockFactor );
- if( !npRoot ){
- iErrorStop = 100;
- iRc = XB_NO_MEMORY;
- throw iRc;
- }
- npTag->ulRootPage = npRoot->ulBlockNo;
-
- // std::cout << "AddKeyNewRoot - RootBlock = " << npRoot->ulBlockNo << "\n";
- // std::cout << "AddKeyNewRoot - LeftBlock = " << npLeft->ulBlockNo << "\n";
- // std::cout << "AddKeyNewRoot - RightBlock = " << npRight->ulBlockNo << "\n";
-
-
- pLastKey = (char *) malloc( (size_t) npTag->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 += 8;
- ePutUInt32( pTrg, npLeft->ulBlockNo * (xbUInt32) iBlockFactor );
-
- // set the key
- pTrg+= 4;
- // std::cout << "AddKeyNewRoot - key [" << pLastKey << "] len = [" << strlen( pLastKey) << "]\n";
- memcpy( pTrg, pLastKey, (size_t) npTag->iKeyLen );
-
- // set the right node number
- //pTrg+= (npTag->iKeyLen);
- // pTrg+= (npTag->iKeyItemLen)-4;
-
- pTrg+= npTag->iKeyItemLen - 4;
-
- //pTrg-=4;
-
- ePutUInt32( pTrg, npRight->ulBlockNo * (xbUInt32) iBlockFactor );
-
- // write out the new block
- if(( iRc = WriteBlock( npRoot->ulBlockNo, GetBlockSize(), npRoot->cpBlockData )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
-
- // write out the new root node number in the tag header
- // position the file
- xbUInt32 ulPagePos = npTag->ulTagHdrPageNo * 512;
-
- // std::cout << "ulPagePos = " << ulPagePos << " root block no = " << npRoot->ulBlockNo << " \n";
-
- // save the number to a buffer
- char cBuf[4];
- ePutUInt32( cBuf, npRoot->ulBlockNo * ((xbUInt32) iBlockFactor ));
-
- if(( iRc = xbFseek( ulPagePos, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- if(( iRc = xbFwrite( &cBuf, 4, 1 )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
-
- if( pLastKey )
- free( pLastKey );
-
- npRoot = FreeNodeChain( npRoot );
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::AddKeyNewRoot() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- if( pLastKey )
- free( pLastKey );
- }
- return iRc;
-}
-
-
-
-/***********************************************************************/
-//! @brief Allocate a node.
-/*!
- \param mpTag Pointer to mdx tag
- \param ulBufSize Buffer size.
- \param ulBlock2 Value to load in ulBlock2 field, bytes 4-7 in the first page of the block
- \returns Pointer to new node.
-*/
-xbIxNode * xbIxMdx::AllocateIxNode( xbMdxTag * mpTag, xbUInt32 ulBufSize, xbUInt32 ulBlock2 ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbIxNode *n = NULL;
-
- try{
-
- // std::cout << "xbIxMdx::AllocateIxNode()\n";
-
- if(( n = xbIx::AllocateIxNode( ulBufSize )) == NULL ){
- iRc = XB_NO_MEMORY;
- iErrorStop = 100;
- throw iRc;
- }
- char *p = n->cpBlockData;
- p += 4;
-
- if( ulFirstFreePage > 0 && bReuseEmptyNodes ){
- // we have an empty node we can reuse
-
- // std::cout << "Reusing node " << ulFirstFreePage << "\n";
-
- n->ulBlockNo = PageToBlock( ulFirstFreePage );
- if(( iRc = ReadBlock( n->ulBlockNo, GetBlockSize(), n->cpBlockData )) != XB_NO_ERROR ){
- iRc = 110;
- throw iRc;
- }
- // update ulFirstFreePage
- ulFirstFreePage = eGetUInt32( p );
- if(( iRc = xbFseek( 36, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- if(( iRc = xbFwrite( p, 4, 1 )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- // memset cpBlockData to zeroes
- memset( n->cpBlockData, 0x00, GetBlockSize());
-
-
- } else {
- n->ulBlockNo = ulPageCnt / (xbUInt32) iBlockFactor;
- ulPageCnt += (xbUInt32) iBlockFactor;
- }
-
- mpTag->ulTagSize += (xbUInt32) iBlockFactor;
- if( ulBlock2 > 0 ){
- ePutUInt32( p, ulBlock2 );
- }
-
- // std::cout << "AllocateIxNode incremented the block to " << ulPageCnt << "\n";
- // std::cout << "AllocateIxNode new block number = " << n->ulBlockNo << "\n";
- }
- catch( xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::AllocateIxNode() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- if( n )
- n = FreeNodeChain( n );
- }
-
- return n;
-
-}
-/***********************************************************************/
-//! @brief Calculate B-tree pointers.
-/*!
- Set binary tree pointer value. The MDX tags are stored with binary
- tree positions. This routine calculates the value in memory.
- \returns void
-*/
-
-void xbIxMdx::CalcBtreePointers(){
-
- xbInt16 iaLeftChild[48];
- xbInt16 iaRightChild[48];
- xbInt16 iaParent[48];
-
- for( xbInt16 i = 0; i < 48; i++ ){
- iaLeftChild[i] = 0;
- iaRightChild[i] = 0;
- iaParent[i] = 0;
- }
-
- // anything to do?
- if( iTagUseCnt > 1 ){
- xbString sBaseTag;
- xbString sThisTag;
- xbString sWorkTag;
- xbInt16 iWorkTagNo;
- xbBool bDone;
- sBaseTag = GetTagName( GetTag( 0 ));
-
- for( xbInt16 iThisTagNo = 1; iThisTagNo < iTagUseCnt; iThisTagNo++ ){
- iWorkTagNo = 0;
- sWorkTag.Set( sBaseTag );
- sThisTag = GetTagName( GetTag( iThisTagNo ));
- bDone = xbFalse;
- while( !bDone ){
- if( sThisTag < sWorkTag ){
- if( iaLeftChild[iWorkTagNo] == 0 ) {
- iaLeftChild[iWorkTagNo] = iThisTagNo + 1;
- iaParent[iThisTagNo] = iWorkTagNo + 1;
- bDone = xbTrue;
- } else {
- iWorkTagNo = iaLeftChild[iWorkTagNo]-1;
- sWorkTag = GetTagName( GetTag( iWorkTagNo));
- }
- } else {
- if( iaRightChild[iWorkTagNo] == 0 ) {
- iaRightChild[iWorkTagNo] = iThisTagNo + 1;
- iaParent[iThisTagNo] = iWorkTagNo + 1;
- bDone = xbTrue;
- } else {
- iWorkTagNo = iaRightChild[iWorkTagNo]-1;
- sWorkTag = GetTagName( GetTag( iWorkTagNo ));
- }
- }
- }
- }
- }
-
- xbString s;
- xbMdxTag *mpTag = mdxTagTbl;
- for( xbInt16 i = 0; i < iTagUseCnt; i++ ){
-// s.Sprintf( "tag = [%d] parent = [%d] left = [%d] right = [%d]\n", i, iaParent[i], iaLeftChild[i], iaRightChild[i]);
-// std::cout << s;
- mpTag->cLeftChild = (char ) iaLeftChild[i];
- mpTag->cRightChild = (char ) iaRightChild[i];
- mpTag->cParent = (char ) iaParent[i];
- mpTag = mpTag->next;
- }
-}
-
-/**************************************************************************************************************/
-//! @brief Calculate the page number for a given block
-/*!
- This routine is called by any function needing to calculate the page number for a given block.
- Page numbers are stored internally in the physical file, and the library reads and writes in
- blocks of one or more pages.
-
- Assumes valid data input
-
- \param ulBlockNo Block Number
- \returns Calculated page number.
-*/
-
-inline xbUInt32 xbIxMdx::BlockToPage( xbUInt32 ulBlockNo ){
- return ulBlockNo * (xbUInt32) iBlockFactor;
-}
-/***********************************************************************/
-char xbIxMdx::CalcTagKeyFmt( xbExp &exp ){
-
- xbExpNode *n = exp.GetTreeHandle();
- if( n->GetChildCnt() == 0 && n->GetNodeType() == XB_EXP_FIELD )
- return 0x01;
- else
- return 0;
-}
-/***********************************************************************/
-//! @brief Check for duplicate key.
-/*!
- \param vpTag Tag to check.
- \returns XB_KEY_NOT_UNIQUE<br>XB_NO_ERROR
-*/
-
-xbInt16 xbIxMdx::CheckForDupKey( void *vpTag )
-{
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbMdxTag *mpTag = (xbMdxTag *) vpTag;
- mpTag->bFoundSts = xbFalse;
- try{
- if( GetUnique( mpTag )){
- if( mpTag->iKeySts == XB_ADD_KEY || mpTag->iKeySts == XB_UPD_KEY )
- if( KeyExists( mpTag )){
- if( GetUniqueKeyOpt() == XB_EMULATE_DBASE ){
- mpTag->bFoundSts = xbTrue;
- return 0;
- } else {
- return XB_KEY_NOT_UNIQUE;
- }
- }
- }
- return 0;
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::CheckForDupKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- 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 xbIxMdx::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;
- xbMdxTag *npTag = (xbMdxTag *) vpTag;
- xbBool bDescending = npTag->cKeyFmt2 & 0x08;
-
- #ifdef XB_LOCKING_SUPPORT
- xbBool bLocked = xbFalse;
- #endif
-
-
- try{
-// xbase->WriteLogMessage( "xbIxMdx::CheckTagIntegrity()", iOpt );
-
- #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 );
- // memset( npTag->cpKeyBuf2, 0x00, (size_t) npTag->iKeyItemLen );
- cKeyType = GetKeyType( vpTag );
-
- pPrevKeyBuf = (char *) calloc( 1, (size_t) npTag->iKeyLen );
- iRc = GetFirstKey( vpTag, 0 );
-
- memcpy( pPrevKeyBuf, GetKeyData( npTag->npCurNode, npTag->npCurNode->iCurKeyNo, npTag->iKeyItemLen ), (size_t) npTag->iKeyLen );
-
- // for each key in the index, make sure it is trending in the right direction
- 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 && !bDescending ) || ( iRc2 > 0 && bDescending )){
- 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;
- }
- }
-
- xbUInt32 ulDbfCnt = 0;
- if(( iRc = dbf->GetRecordCnt( ulDbfCnt )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
-
- xbUInt32 ulFiltCnt = 0;
- xbBool bFiltered = xbTrue;
- // 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 = 150;
- throw iRc;
- }
- if( npTag->cHasFilter ){
- if(( iRc = npTag->filter->ProcessExpression( 0 )) != XB_NO_ERROR ){
- iErrorStop = 160;
- throw iRc;
- }
- if(( iRc = npTag->filter->GetBoolResult( bFiltered )) != XB_NO_ERROR ){
- iErrorStop = 170;
- throw iRc;
- }
- }
-
- if( bFiltered ){
- if(( iRc = FindKeyForCurRec( vpTag )) != XB_NO_ERROR ){
- ulThisRecNo = j;
- iErrorStop = 180;
- throw iRc;
- }
- ulFiltCnt++;
- }
- }
-
- if((GetUniqueKeyOpt() == XB_EMULATE_DBASE) && (GetUnique( vpTag ))){
- // can't compare counts if using XB_EMULATE_DBASE and it's a unique index
- } else {
- if( ulIxCnt != ulFiltCnt && GetUniqueKeyOpt() == XB_HALT_ON_DUPKEY ){
- if( npTag->cHasFilter )
- sMsg.Sprintf( "xbIxMdx::CheckTagIntegrity() Filtered index entry count [%ld] does not match dbf record count [%ld] for tag [%s]", ulIxCnt, ulFiltCnt, npTag->cTagName );
- else
- sMsg.Sprintf( "xbIxMdx::CheckTagIntegrity() Index entry count [%ld] does not match dbf record count [%ld] for tag [%s]", ulIxCnt, ulFiltCnt, npTag->cTagName );
-
- xbase->WriteLogMessage( sMsg, iOpt );
- iErrorStop = 190;
- iRc = XB_INVALID_INDEX;
- throw iRc;
- }
- if( npTag->cHasFilter )
- sMsg.Sprintf( "xbIxMdx::CheckTagIntegrity() Filtered index entry count [%ld] matches dbf record count [%ld] for tag [%s]", ulIxCnt, ulFiltCnt, npTag->cTagName );
- else
- sMsg.Sprintf( "xbIxMdx::CheckTagIntegrity() Index entry count [%ld] matches dbf record count [%ld] for tag [%s]", ulIxCnt, ulFiltCnt, npTag->cTagName );
- xbase->WriteLogMessage( sMsg, iOpt );
- }
-
-
- if( pPrevKeyBuf )
- free( pPrevKeyBuf );
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::CheckTagIntegrity() Exception Caught. Error Stop = [%d] iRc = [%d] Tag = [%s]", iErrorStop, iRc, npTag->cTagName );
- xbase->WriteLogMessage( sMsg, iOpt );
- xbase->WriteLogMessage( GetErrorMessage( iRc ), iOpt );
- if( pPrevKeyBuf )
- free( pPrevKeyBuf );
-
- if( iErrorStop == 160 ){
- sMsg.Sprintf( "xbIxMdx::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;
-}
-
-/***********************************************************************/
-xbMdxTag *xbIxMdx::ClearTagTable(){
-
- // clear the list of tags
- xbMdxTag *tt = mdxTagTbl;
- xbMdxTag *tt2;
- while( tt ){
- tt2 = tt;
- tt = tt->next;
- tt2->npNodeChain = FreeNodeChain( tt2->npNodeChain );
- tt2->npCurNode = NULL;
- if( tt2->cpKeyBuf )
- free( tt2->cpKeyBuf );
- if( tt2->cpKeyBuf2 )
- free( tt2->cpKeyBuf2 );
- if( tt2->exp )
- delete tt2->exp;
- if( tt2->filter )
- delete tt2->filter;
- if( tt2->sKeyExp )
- delete tt2->sKeyExp;
- if( tt2->sTagName )
- delete tt2->sTagName;
- if( tt2->sFiltExp )
- delete tt2->sFiltExp;
- free( tt2 );
- }
- return NULL;
-}
-/***********************************************************************/
-xbInt16 xbIxMdx::Close(){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
-
- try{
- mdxTagTbl = ClearTagTable();
- if(( iRc = xbIx::Close()) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::Close() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-
-/***********************************************************************/
-//! @brief Create key.
-/*!
-
- \param vpTag Tag
- \param iOpt 1 = Append, 2 = Update
- \returns XB_KEY_NOT_UNIQUE<br>XB_NO_ERROR
-
- iKeySts 0 - No Updates
- 1 - Add Key XB_ADD_KEY
- 2 - Update Key XB_UPD_KEY
- 3 - Delete Key XB_DEL_KEY
-
- bKeyFiltered xbFalse - Key filtered out
- xbTrue - Key filtered in
-
- cpKeyBuf - Key buffer for add
- cpKeyBuf2 - Key buffer for delete
-
-*/
-
-xbInt16 xbIxMdx::CreateKey( void *vpTag, xbInt16 iOpt ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
-
- xbBool bFilter0 = xbFalse; // filter against RecBuf, updated record buffer
- xbBool bFilter1 = xbFalse; // filter against recBuf2, original record buffer
-
- try{
-
- xbMdxTag *npTag = (xbMdxTag *) vpTag;
- npTag->iKeySts = 0;
-
- // char *p0 = dbf->GetRecordBuf(0);
- // char *p1 = dbf->GetRecordBuf(1);
-
- // do tag filter logic
- if( npTag->cHasFilter ){
- if(( iRc = npTag->filter->ProcessExpression( 0 )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- if(( iRc = npTag->filter->GetBoolResult( bFilter0 )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- // std::cout << "cp1 f0 = " << bFilter0 << "\n";
- // printf( "del byte 0 [%x] 1 [%x]\n", *p0, *p1 );
- } else {
- bFilter0 = xbTrue;
- }
-
- // if add request and filtered out, we're done
- if( iOpt == 1 && !bFilter0 )
- return XB_NO_ERROR;
-
- if(( iRc = npTag->exp->ProcessExpression( 0 )) != XB_NO_ERROR ){
- iErrorStop = 120;
- 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 );
- xbBcd bcd( d );
- bcd.ToChar( npTag->cpKeyBuf );
- }
- else if( npTag->exp->GetReturnType() == XB_EXP_DATE ){
- xbDouble d;
- npTag->exp->GetNumericResult( d );
- memcpy( npTag->cpKeyBuf, &d, 8 );
- }
-
- if( iOpt == 1 ) // Append
- npTag->iKeySts = XB_ADD_KEY;
-
- else if( iOpt == 2 ){ // Update
- if( npTag->cHasFilter ){
- if(( iRc = npTag->filter->ProcessExpression( 1 )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- if(( iRc = npTag->filter->GetBoolResult( bFilter1 )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
- } else {
- bFilter1 = xbTrue;
- }
-
- if(( iRc = npTag->exp->ProcessExpression( 1 )) != XB_NO_ERROR ){
- iErrorStop = 150;
- 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 ){
- xbDouble d;
- npTag->exp->GetNumericResult( d );
- xbBcd bcd( d );
- bcd.ToChar( npTag->cpKeyBuf2 );
-
- } else if( npTag->exp->GetReturnType() == XB_EXP_DATE ){
- xbDouble d;
- npTag->exp->GetNumericResult( d );
- memcpy( npTag->cpKeyBuf2, &d, 8 );
-
- }
-
- if( bFilter1 ){ // original key was indexed
- if( bFilter0 ){ // new key s/b indexed, update it if changed
- if( memcmp( npTag->cpKeyBuf, npTag->cpKeyBuf2, (size_t) npTag->iKeyLen )){
- npTag->iKeySts = XB_UPD_KEY;
- }
- } else { // original key indexed, new key not indexed, delete it
- npTag->iKeySts = XB_DEL_KEY;
- }
- } else { // original key not indexed
- if( bFilter0 )
- npTag->iKeySts = XB_ADD_KEY;
- }
- }
-
-// std::cout << "xbIxMdx::CreateKey key sts = " << npTag->iKeySts << " iOpt = " << iOpt << " type = " << npTag->exp->GetReturnType() << " name = " << npTag->cTagName;
-// std::cout << " f0 = " << bFilter0 << " f1 = " << bFilter1 << "\n";
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::CreateKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
-
- return iRc;
-}
-
-/***********************************************************************/
-//! @brief Create new tag.
-/*!
- This routine creates a new tag. When complete, sets the cur tag pointer to
- the newly created tag.
-
- \param sName Tag Name, including .MDX suffix
- \param sKey Key Expression
- \param sFilter Filter expression.
- \param iDescending
- \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 xbIxMdx::CreateTag( const xbString &sName, const xbString &sKey, const xbString &sFilter, xbInt16 iDescending, xbInt16 iUnique, xbInt16 iOverlay, void **vpTag ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbMdxTag *tte = NULL;
-
-
- // std::cout << "CreateTag() name=[" << sName.Str() << "] key=[" << sKey.Str() << "] sFilter=[" << sFilter.Str() << "]\n";
- // std::cout << "TagUseCnt = " << iTagUseCnt << std::endl;
-
-
- try{
- // verify room for new tag
- if( !( iTagUseCnt < 47 )){
- iErrorStop = 100;
- iRc = XB_LIMIT_REACHED;
- throw iRc;
- }
-
- // verify valid tag name
- xbString sWorker = sName;
- sWorker.Trim();
- if( sWorker.Len() > 10 ){
- iErrorStop = 110;
- iRc = XB_INVALID_TAG;
- throw iRc;
- }
-
- // verify tag not already defined
- if( iTagUseCnt > 0 ){
- if( GetTag( sWorker )){
- iErrorStop = 120;
- iRc = XB_INVALID_TAG;
- throw iRc;
- }
- }
-
- // allocate a tag structure here
- if(( tte = (xbMdxTag *) calloc( 1, (size_t) sizeof( xbMdxTag ))) == NULL ){
- iErrorStop = 130;
- iRc = XB_NO_MEMORY;
- throw iRc;
- }
- *vpTag = tte;
- tte->sTagName = new xbString( sWorker );
-
- //set up the key expression
- sWorker = sFilter;
- sWorker.Trim();
- if( sWorker.Len() > 0 ){
- if( sWorker.Len() == 0 || sWorker.Len() > 220 ){
- iRc = XB_INVALID_TAG;
- iErrorStop = 140;
- throw iRc;
- }
- tte->sFiltExp = new xbString( sWorker );
- tte->filter = new xbExp( dbf->GetXbasePtr());
- if(( iRc = tte->filter->ParseExpression( dbf, sWorker )) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
-
- // tte->filter->DumpTree( 1 );
-
- if((tte->filter->GetReturnType()) != 'L' ){
- iRc = XB_INVALID_TAG;
- iErrorStop = 160;
- throw iRc;
- }
- tte->cHasFilter = 0x01;
- }
-
- //set up the key expression
- sWorker = sKey;
- sWorker.Trim();
- if( sWorker.Len() == 0 || sWorker.Len() > 100 ){
- iRc = XB_INVALID_TAG;
- iErrorStop = 170;
- throw iRc;
- }
- tte->sKeyExp = new xbString( sWorker );
- tte->exp = new xbExp( dbf->GetXbasePtr());
- if(( iRc = tte->exp->ParseExpression( dbf, sWorker )) != XB_NO_ERROR ){
- iErrorStop = 180;
- throw iRc;
- }
-
- xbDate d;
-
- if( iTagUseCnt == 0 ){
- // first tag, new mdx file
- // create the file name
- xbString sIxFileName = dbf->GetFqFileName();
- sIxFileName.Trim();
- xbUInt32 lLen = sIxFileName.Len();
- sIxFileName.PutAt( lLen-2, 'M' );
- sIxFileName.PutAt( lLen-1, 'D' );
- sIxFileName.PutAt( lLen, 'X' );
-
- // copy the file name to the class variable
- this->SetFileName( sIxFileName );
- if( FileExists() && !iOverlay ){
- iErrorStop = 190;
- iRc = XB_FILE_EXISTS;
- throw iRc;
- }
-
- // first tag, need to create the file
- if(( iRc = xbFopen( "w+b", dbf->GetShareMode())) != XB_NO_ERROR ){
- iErrorStop = 200;
- throw iRc;
- }
- cVersion = 2;
- cCreateYY = (char) d.YearOf() - 1900;
- cCreateMM = (char) d.MonthOf();
- cCreateDD = (char) d.DayOf( XB_FMT_MONTH );
-
- GetFileNamePart( sFileName );
- sFileName.ToUpperCase();
-
- SetBlockSize( (xbUInt32) dbf->GetCreateMdxBlockSize());
- iBlockFactor = GetBlockSize() / 512;
-
- cProdIxFlag = 1;
- cTagEntryCnt = 48;
- iTagLen = 32;
- ulPageCnt = 4;
- ulFirstFreePage = 0;
- ulNoOfBlockAvail = 0;
- cNextTag = 1;
- c1B = 0x1B;
- cUpdateYY = cCreateYY;
- cUpdateMM = cCreateMM;
- cUpdateDD = cCreateDD;
-
- if(( iRc = WriteHeadBlock( 0 )) != XB_NO_ERROR ){
- iErrorStop = 210;
- throw iRc;
- }
- }
-
- // populate the tag table entry structure
- tte->ulTagHdrPageNo = ulPageCnt;
- ulPageCnt += (xbUInt32) iBlockFactor;
- tte->sTagName->strncpy( tte->cTagName, 10 );
-
- // cKeyFmt is always 0x10;
- // tested 2+ZIPCD CITY+STATE or just standalone field - always 0x10
- tte->cKeyFmt = 0x10; // = CalcTagKeyFmt( *tte->exp );
-
- switch( tte->exp->GetReturnType()){
- case XB_EXP_CHAR:
- tte->cKeyType = 'C';
- tte->iKeyLen = tte->exp->GetResultLen();
- tte->iSecKeyType = 0;
- break;
-
- case XB_EXP_NUMERIC:
- tte->cKeyType = 'N';
- tte->iKeyLen = 12;
- tte->iSecKeyType = 0;
- break;
-
- case XB_EXP_DATE:
- tte->cKeyType = 'D';
- tte->iKeyLen = 8;
- tte->iSecKeyType = 1;
- break;
-
- default:
- iErrorStop = 200;
- iRc = XB_INVALID_INDEX;
- throw iRc;
- }
-
- tte->cpKeyBuf = (char *) malloc( (size_t) tte->iKeyLen + 1 );
- tte->cpKeyBuf2 = (char *) malloc( (size_t) tte->iKeyLen + 1 );
-
-// if( 0 ){
-// printf( "ulTagHdrPageNo=[%d] cTagName=[%-11s], cLeftChild=[%d] cRightChild=[%d] cParent=[%d] cKeyType=[%c]\n\n",
-// tte->ulTagHdrPageNo, tte->cTagName, tte->cLeftChild, tte->cRightChild, tte->cParent, tte->cKeyType );
-// }
-
- // write the new tte entry here
- char tteBuf[21];
- memset( tteBuf, 0x00, 21 );
-
- ePutUInt32( &tteBuf[0], tte->ulTagHdrPageNo );
- for( xbUInt32 l = 0; l < tte->sTagName->Len() && l < 10; l++ ){
- tteBuf[l+4] = tte->sTagName->GetCharacter(l+1);
- }
- tteBuf[15] = tte->cKeyFmt;
- tteBuf[19] = 0x02; // appears to always be a 0x02
- tteBuf[20] = tte->cKeyType;
-
- if(( iRc = xbFseek( (iTagUseCnt * 32) + 544, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 210;
- throw iRc;
- }
- if(( iRc = xbFwrite( tteBuf, 21, 1 )) != XB_NO_ERROR ){
- iErrorStop = 220;
- throw iRc;
- }
-
-
- // Begin Tag Header
- tte->ulRootPage = ulPageCnt;
- tte->ulTagSize = (xbUInt32) iBlockFactor;
- ulPageCnt += 2;
- tte->cKeyFmt2 = 0x10;
- if( iDescending )
- tte->cKeyFmt2 += 0x08;
- if( iUnique ){
- tte->cKeyFmt2 += 0x40;
- tte->cUnique = 0x01;
- }
-
- tte->cTag11 = 0x1B; // always 0x1b ?
- tte->cSerialNo = 0x01; // version incremented with each tag update
- tte->ulLeftChild = tte->ulRootPage;
- tte->ulRightChild = tte->ulRootPage;
-
- tte->cTagYY = (char) d.YearOf() - 1900;
- tte->cTagMM = (char) d.MonthOf();
- tte->cTagDD = (char) d.DayOf( XB_FMT_MONTH );
-
- tte->cKeyType2 = tte->cKeyType;
- tte->iKeyItemLen = tte->iKeyLen + 4;
- while(( tte->iKeyItemLen % 4 ) != 0 ) tte->iKeyItemLen++;
-
- tte->iKeysPerBlock = (xbInt16) (GetBlockSize() - 12) / tte->iKeyItemLen;
-
- //std::cout << "-------------- create tag info\n";
- //std::cout << "keylen=" << tte->iKeyLen << " iKeyItemLen = " << tte->iKeyItemLen << " keys per block calc = " << tte->iKeysPerBlock << "\n";
-
- tte->cKeyFmt3 = CalcTagKeyFmt( *tte->exp );
-
-// printf( "ulRootPage=[%d] cKeyFmt2=[%d] cKeyType2=[%d] iKeyLen=[%d]iKeysPerBlock=[%d]\n", tte->ulRootPage, tte->cKeyFmt2, tte->cKeyType2, tte->iKeyLen, tte->iKeysPerBlock );
-// printf( "iSecKeyType=[%d] iKeyItemLen=[%d] cUnique=[%d] \n", tte->iSecKeyType, tte->iKeyItemLen, tte->cUnique );
-
- char *pBuf;
- if(( pBuf = (char *) calloc( 1, (size_t) GetBlockSize())) == NULL ){
- iErrorStop = 230;
- iRc = XB_NO_MEMORY;
- throw iRc;
- }
- char *wPtr;
- wPtr = pBuf;
- ePutUInt32( wPtr, tte->ulRootPage );
-
- wPtr += 4;
- ePutUInt32( wPtr, tte->ulTagSize );
-
- wPtr += 4;
- *wPtr = tte->cKeyFmt2;
-
- wPtr++;
- *wPtr = tte->cKeyType2;
-
- wPtr += 2;
- *wPtr = tte->cTag11;
-
- wPtr += 1;
- ePutInt16( wPtr, tte->iKeyLen );
-
- wPtr += 2;
- ePutInt16( wPtr, tte->iKeysPerBlock );
-
- wPtr += 2;
- ePutInt16( wPtr, tte->iSecKeyType );
-
- wPtr += 2;
- ePutInt16( wPtr, tte->iKeyItemLen );
-
- wPtr += 2;
- *wPtr = tte->cSerialNo;
-
- wPtr += 3;
- *wPtr = tte->cUnique;
-
- wPtr++;
- for( xbUInt32 l = 0; l < tte->sKeyExp->Len(); l++ )
- *wPtr++ = tte->sKeyExp->GetCharacter(l+1);
-
- wPtr = pBuf;
-
- tte->cHasKeys = 0x00;
- pBuf[246] = tte->cHasKeys;
-
- wPtr += 248;
- ePutUInt32( wPtr, tte->ulLeftChild );
- wPtr += 4;
- ePutUInt32( wPtr, tte->ulRightChild );
-
- pBuf[257] = tte->cTagYY;
- pBuf[258] = tte->cTagMM;
- pBuf[259] = tte->cTagDD;
- pBuf[480] = tte->cKeyFmt3;
-
- if( sFilter.Len() > 0 ){
- pBuf[245] = tte->cHasFilter;
- wPtr = pBuf;
- wPtr += 762;
- for( xbUInt32 l = 0; l < sFilter.Len(); l++ )
- *wPtr++ = sFilter.GetCharacter(l+1);
- }
-
- if(( iRc = xbFseek( tte->ulTagHdrPageNo * 512, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 240;
- throw iRc;
- }
-
- if(( iRc = xbFwrite( pBuf, GetBlockSize(), 1 )) != XB_NO_ERROR ){
- iErrorStop = 250;
- throw iRc;
- }
-
- memset( pBuf, 0x00, GetBlockSize() );
- if(( iRc = xbFwrite( pBuf, GetBlockSize(), 1 )) != XB_NO_ERROR ){
- iErrorStop = 260;
- throw iRc;
- }
-
- iTagUseCnt++;
- cNextTag++;
-
-
- if(( iRc = WriteHeadBlock( 1 )) != XB_NO_ERROR ){
- iErrorStop = 270;
- throw iRc;
- }
-
- // update the dbf file if needed - discreet field, has no filter
- // 10/15/22 - dbase 7 does not update this field on index creation
- if( tte->cKeyFmt3 == 0x01 && !tte->cHasFilter ){
- // printf( "cKeyFmt3 = [%x]\n", tte->cKeyFmt3 );
- xbInt16 iFldNo;
- if(( iRc = dbf->GetFieldNo( sKey, iFldNo )) != XB_NO_ERROR ){
- iErrorStop = 280;
- throw iRc;
- }
- xbInt64 lOffset = 31 + ((iFldNo + 1) * 32 );
-
- if(( iRc = dbf->xbFseek( lOffset, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 290;
- iRc = XB_SEEK_ERROR;
- throw iRc;
- }
- char cBuf[2];
- cBuf[0] = 0x01;
- cBuf[1] = 0x00;
-
- if(( iRc = dbf->xbFwrite( cBuf, 1, 1 )) != XB_NO_ERROR ){
- iErrorStop = 300;
- throw iRc;
- }
- dbf->UpdateSchemaIxFlag( iFldNo, 0x01 );
- }
-
- // add the new entry to the end of the list of tags
- if( mdxTagTbl == NULL ){
- mdxTagTbl = tte;
- } else {
- xbMdxTag *tteL = mdxTagTbl;
- while( tteL->next )
- tteL = tteL->next;
- tteL->next = tte;
- }
-
- /* update the btree pointers */
- CalcBtreePointers();
- char bBuf[3];
- xbMdxTag *tteWork = mdxTagTbl;
-
- if(( iRc = xbFseek( 560, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 310;
- throw iRc;
- }
- while( tteWork ){
- bBuf[0] = tteWork->cLeftChild;
- bBuf[1] = tteWork->cRightChild;
- bBuf[2] = tteWork->cParent;
-
- if(( iRc = xbFwrite( bBuf, 3, 1 )) != XB_NO_ERROR ){
- iErrorStop = 320;
- throw iRc;
- }
- if( tteWork->next ){
- if(( iRc = xbFseek( 29, SEEK_CUR )) != XB_NO_ERROR ){
- iErrorStop = 330;
- throw iRc;
- }
- }
- tteWork = tteWork->next;
- }
- free( pBuf );
-
-// xbIx::SetCurTag( ( void *) tte );
-
- }
-
- catch (xbInt16 iRc ){
- if( tte ){
- if( tte->cpKeyBuf )
- free( tte->cpKeyBuf );
- if( tte->cpKeyBuf2 )
- free( tte->cpKeyBuf2 );
- if( tte->exp )
- delete tte->exp;
- if( tte->filter )
- delete tte->filter;
- if( tte->sKeyExp )
- delete tte->sKeyExp;
- if( tte->sFiltExp )
- delete tte->sFiltExp;
- if( tte->sTagName )
- delete tte->sTagName;
- free( tte );
- }
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::CreateTag() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
-
- return iRc;
-};
-
-/***********************************************************************/
-//! @brief Delete a key from a node.
-/*!
- 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 xbIxMdx::DeleteFromNode( void *vpTag, xbIxNode * npNode, xbInt16 iSlotNo )
-{
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbMdxTag * npTag = (xbMdxTag *) vpTag;
-
- try{
- xbInt32 lKeyCnt = GetKeyCount( npNode );
- xbInt16 iLen = (lKeyCnt - iSlotNo - 1) * npTag->iKeyItemLen;
- xbBool bLeaf = IsLeaf( vpTag, npNode );
- if( !bLeaf )
- iLen += 4;
-
- char *pTrg = npNode->cpBlockData;
- if( iLen > 0 ){
- pTrg += (8 + (npTag->iKeyItemLen * (iSlotNo)) ); //lTrgPos;
- // std::cout << "TrgSpot = " << (8 + (npTag->iKeyItemLen * (iSlotNo)) ) << "\n";
- char *pSrc = pTrg;
- pSrc += npTag->iKeyItemLen;
- memmove( pTrg, pSrc, (size_t) iLen );
- }
-
- // zap out the right most key
- pTrg = npNode->cpBlockData;
- if( bLeaf ){
- pTrg += (8 + (npTag->iKeyItemLen * ( lKeyCnt-1 )));
-
- } else {
- pTrg += (12 + (npTag->iKeyItemLen * ( lKeyCnt-1 )));
-
- }
-
- for( xbInt16 i = 0; i < npTag->iKeyItemLen; i++ )
- *pTrg++ = 0x00;
-
- // set the new number of keys
- ePutUInt32( npNode->cpBlockData, (xbUInt32) lKeyCnt - 1 );
-
- // if node empty, add it to the free node chain
- if( lKeyCnt < 2 ){
- if( bReuseEmptyNodes ){
- if( bLeaf && lKeyCnt == 1 ){
- if(( iRc = HarvestEmptyNode( npTag, npNode, 0 )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- }
- }
- }
-
- // write out the block
- if(( iRc = WriteBlock( npNode->ulBlockNo, GetBlockSize(), npNode->cpBlockData )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
-
- // do any empty node processing here
-// if( bReuseEmptyNodes ){
-// if( bLeaf && lKeyCnt == 1 ){
-// std::cout << "Empty node ready for reuse\n";
-// }
-// }
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::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 xbIxMdx::DeleteKey( void *vpTag ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbMdxTag * npTag = (xbMdxTag *) vpTag;
-
- // save copy of node chain to reset to after delete completed
- xbIxNode *npSaveNodeChain = npTag->npNodeChain;
- npTag->npNodeChain = NULL;
- xbIxNode * npSaveCurNode = npTag->npCurNode;
-
- // std::cout << "xbIxMdx::DeleteKey()\n";
-
- try{
- xbString sMsg;
-
- if(( iRc = xbIxMdx::KeySetPosDel( npTag )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- // Delete key needs to handle two scenarios
- // 1 - if delete is on the only key of leaf,
- // traverse up tree, trim as needed
- // 2 - if last key on node is deleted, and key value is not the same
- // as prev key, ascend 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;
- }
- } else if(( iRc = HarvestEmptyNode( npTag, npTag->npCurNode, 1 )) != XB_NO_ERROR ){
- iErrorStop = 130;
- 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->ulRootPage && 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 = 140;
- 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;
-
- // update the serial number
- if(( iRc = TagSerialNo( 3, npTag )) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::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 Dump a given block for a tag
-/*!
- \param vpTag Input tag ptr for tag to be deleted<br>
- \returns <a href="xbretcod_8h.html">Return Codes</a><br>
- 1 = Deleted entire MDX file, only had one tag
-
-*/
-
-xbInt16 xbIxMdx::DeleteTag( void *vpTag ){
-
- xbInt16 iRc = 0;
- xbInt16 iErrorStop = 0;
- xbMdxTag * mpTag = (xbMdxTag *) vpTag;
- xbIxNode *n = NULL;
- xbBool bLoneTag = xbFalse;
-
- try{
-
- if( !vpTag ){
- iErrorStop = 100;
- iRc = XB_INVALID_TAG;
- throw iRc;
- }
-
- char cSaveHasFilter = mpTag->cHasFilter;
- char cSaveKeyFmt3 = mpTag->cKeyFmt3;
- xbString sSaveKey = mpTag->sKeyExp->Str();
-
- if( iTagUseCnt == 1 ){
- // std::cout << "xbIxMdx::DeleteTag - one tag found, delete the mdx file\n";
-
- // close the mdx file
- if(( iRc = xbIxMdx::Close()) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
-
- // delete the file
- xbRemove();
-
- // init variables - needed?
- // Init();
- // iRc > 0 defines this as the only tag in an MDX file, MDX file deleted.
- // signals to the calling process to drop the MDX file from the
- // list of updateable indices.
- bLoneTag = xbTrue;
-
- } else {
-
- // harvest tag nodes
-
- if(( iRc = HarvestTagNodes( mpTag, xbTrue )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
-
- // remove an entry from tag table
- // which tag is this?
- xbInt16 iTagNo = 0;
- xbMdxTag *mp = mdxTagTbl;
- xbMdxTag *mpPrev = NULL;
- while( mp && mp->ulTagHdrPageNo != mpTag->ulTagHdrPageNo ){
- iTagNo++;
- mpPrev = mp;
- mp = mp->next;
- }
-
- // remove it from the linked list of tags
- if( !mpPrev ){
- mdxTagTbl = mp->next;
- } else {
- mpPrev->next = mp->next;
- }
- if( mp ){
- if( mp->cpKeyBuf ) free( mp->cpKeyBuf );
- if( mp->cpKeyBuf2 ) free( mp->cpKeyBuf2 );
- if( mp->exp ) delete mp->exp;
- if( mp->filter ) delete mp->filter;
- if( mp->sKeyExp ) delete mp->sKeyExp;
- if( mp->sFiltExp ) delete mp->sFiltExp;
- if( mp->sTagName ) delete mp->sTagName;
- free( mp );
- }
- xbInt32 iTarg = iTagNo * 32;
- xbInt32 iSrc = iTarg + 32;
- xbInt32 iLen = (iTagUseCnt - iTagNo) * 32;
-
- if(( iRc = xbFseek( 544, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 160;
- throw iRc;
- }
- char Buf[1536]; // 47 tags + 1 in case tag #47 is deleted
- memset( Buf, 0x00, 1536 );
- if(( iRc = xbFread( Buf, 1504, 1 )) != XB_NO_ERROR ){
- iErrorStop = 170;
- throw iRc;
- }
- char *pTrg = Buf;
- pTrg += iTarg;
- char *pSrc = Buf;
- pSrc += iSrc;
- for( xbInt32 i = 0; i < iLen; i++ )
- *pTrg++ = *pSrc++;
-
- if(( iRc = xbFseek( 544, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 180;
- throw iRc;
- }
- if(( iRc = xbFwrite( Buf, 1504, 1 )) != XB_NO_ERROR ){
- iErrorStop = 190;
- throw iRc;
- }
-
- iTagUseCnt--;
- if(( iRc = WriteHeadBlock( 1 )) != XB_NO_ERROR ){
- iErrorStop = 200;
- throw iRc;
- }
-
- /* update the btree pointers */
- CalcBtreePointers();
- char bBuf[3];
- xbMdxTag *tteWork = mdxTagTbl;
-
- if(( iRc = xbFseek( 560, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 210;
- throw iRc;
- }
- while( tteWork ){
- bBuf[0] = tteWork->cLeftChild;
- bBuf[1] = tteWork->cRightChild;
- bBuf[2] = tteWork->cParent;
-
- if(( iRc = xbFwrite( bBuf, 3, 1 )) != XB_NO_ERROR ){
- iErrorStop = 320;
- throw iRc;
- }
- if( tteWork->next ){
- if(( iRc = xbFseek( 29, SEEK_CUR )) != XB_NO_ERROR ){
- iErrorStop = 330;
- throw iRc;
- }
- }
- tteWork = tteWork->next;
- }
- }
-
- // update the dbf file if needed, if discreet field with no filter
- // printf( "cSaveKeyFmt3 = [%x] cSaveHasFilter=[%x] SaveKey = [%s]\n", cSaveKeyFmt3, cSaveHasFilter, sSaveKey.Str());
-
- if( cSaveKeyFmt3 == 0x01 && !cSaveHasFilter ){
- xbInt16 iFldNo;
- if(( iRc = dbf->GetFieldNo( sSaveKey, iFldNo )) != XB_NO_ERROR ){
- iErrorStop = 340;
- throw iRc;
- }
- xbInt64 lOffset = 31 + ((iFldNo + 1) * 32 );
-
- if(( iRc = dbf->xbFseek( lOffset, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 350;
- iRc = XB_SEEK_ERROR;
- throw iRc;
- }
- char cBuf[2];
- cBuf[0] = 0x00;
- cBuf[1] = 0x00;
- if(( iRc = dbf->xbFwrite( cBuf, 1, 1 )) != XB_NO_ERROR ){
- iErrorStop = 360;
- throw iRc;
- }
- dbf->UpdateSchemaIxFlag( iFldNo, 0x00 );
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::DeleteTag() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- if( n )
- free( n );
- }
- if( bLoneTag && !iRc )
- return 1;
- else
- return iRc;
-}
-
-/***********************************************************************/
-#ifdef XB_DEBUG_SUPPORT
-
-//! @brief Dump a given block for a tag
-/*!
- \param iOpt Output message destination<br>
- 0 = stdout<br>
- 1 = Syslog<br>
- 2 = Both<br>
- \param ulBlockNo Block number to dump
- \param mpTag Index tag pointer
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-
-*/
-
-xbInt16 xbIxMdx::DumpBlock( xbInt16 iOpt, xbUInt32 ulBlockNo, xbMdxTag *mpTag ){
-
- xbInt16 iRc = 0;
- xbInt16 iErrorStop = 0;
- xbString s, s2;
- xbBool bLeaf;
- char *p;
-
- try{
- if(( iRc = GetBlock( mpTag, ulBlockNo, 0 )) != XB_NO_ERROR ){
- iErrorStop = 10;
- throw iRc;
- }
- p = cNodeBuf;
- xbInt32 lNoOfKeys = eGetInt32( p );
- p+=4;
- xbUInt32 ulNode2 = eGetUInt32( p );
-
- if( !mpTag ){
- // if no tag info, print what is available without tag info and exit
- s.Sprintf( "--- BlkNo = %ld Page = %ld NoOfKeys = %ld Node2 (opt NextFreePage) = %ld", ulBlockNo, BlockToPage( ulBlockNo ), lNoOfKeys, ulNode2 );
- xbase->WriteLogMessage( s, iOpt );
- return XB_NO_ERROR;
- }
-
- p+=4;
- p+= mpTag->iKeyItemLen * lNoOfKeys;
- if( eGetUInt32( p ) == 0 ){
- bLeaf = xbTrue;
- // std::cout << "No of keys = " << lNoOfKeys << "\n";
- s.Sprintf( "--- Leaf Node KeyCnt %d\t Page %d\t Block %d", lNoOfKeys, BlockToPage( ulBlockNo ), ulBlockNo );
- } else {
- bLeaf = xbFalse;
- s.Sprintf( "--- Interior Node KeyCnt %d\t Page %d\t Block %d", lNoOfKeys, BlockToPage( ulBlockNo ), ulBlockNo );
- }
- if( ulNode2 > 0 )
- s.Sprintf( "%s Node2 (opt NextFreePage) = %d", s.Str(), ulNode2 );
-
- xbase->WriteLogMessage( s, iOpt );
-
- xbInt32 l;
- for( l = 0; l < lNoOfKeys; l++ ){
- p = cNodeBuf + (8 + (l * mpTag->iKeyItemLen ));
- s.Sprintf( "%08ld\t", eGetUInt32( p ));
- p+=4;
- if( mpTag->cKeyType2 == 'C' ){ //CHAR
- for( xbInt32 l = 0; l < (mpTag->iKeyItemLen-4); l++ )
- s += *p++;
- s.Trim();
- } else if( mpTag->cKeyType2 == 'N' ){ // NUMERIC
- xbBcd bcd( p );
- bcd.ToString( s2 );
- s += s2;
- } else if( mpTag->cKeyType2 == 'D' ){ // DATE
- xbInt32 lDate = (xbInt32) eGetDouble( p );
- xbDate d( lDate );
- s.Sprintf( "%s\t%ld\t(%s)", s.Str(), lDate, d.Str());
- } else {
- s.Sprintf( "Unknown key type [%c]", mpTag->cKeyType2 );
- }
- xbase->WriteLogMessage( s, iOpt );
- }
- if( !bLeaf ){
- // interior node has one extra key at the right most position
- p = cNodeBuf + (8 + (l * mpTag->iKeyItemLen ));
- s.Sprintf( "\t%08ld", eGetUInt32( p ));
- xbase->WriteLogMessage( s, iOpt );
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::DumpBlock() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/**************************************************************************************************************/
-//! @brief Dump free blocks.
-/*!
- Dump free blocks for index 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 xbIxMdx::DumpFreeBlocks( xbInt16 iOpt ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbString s;
- char *pBuf = NULL;
- char *pNextPage;
- xbUInt32 ulNextPage;
-
- try{
-
- if(( iRc = ReadHeadBlock( 1 )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
-
- xbUInt32 ulLastBlock = PageToBlock( ulPageCnt );
-
- pBuf = (char *) malloc( (size_t) GetBlockSize());
- if( !pBuf ){
- iErrorStop = 110;
- iRc = XB_NO_MEMORY;
- throw iRc;
- }
-
- if( ulFirstFreePage > 0 ){
- xbUInt32 ulThisFreePage = ulFirstFreePage;
- xbUInt32 ulNextFreePage = 0;
- xbUInt32 ulCnt = 0;
- xbase->WriteLogMessage( "*** Free Blocks ***", iOpt );
- s.Sprintf( "File Header - FirstFreePage = %ld Block = %ld", ulFirstFreePage, PageToBlock( ulFirstFreePage ));
- xbase->WriteLogMessage( s, iOpt );
- while( ulThisFreePage > 0 ){
- if(( iRc = ReadBlock( PageToBlock( ulThisFreePage ), GetBlockSize(), pBuf )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- pNextPage = pBuf;
- pNextPage+=4;
- ulNextFreePage = eGetUInt32( pNextPage );
- s.Sprintf( "Free Page# = %ld\t(Block# = %ld)\tNext Free Page = %ld\t(Block = %ld)", ulThisFreePage, PageToBlock( ulThisFreePage ), ulNextFreePage, PageToBlock( ulNextFreePage ));
- xbase->WriteLogMessage( s, iOpt );
- ulThisFreePage = ulNextFreePage;
- ulCnt++;
- }
- s.Sprintf( "%ld free blocks (%ld pages)", ulCnt, BlockToPage( ulCnt ));
- xbase->WriteLogMessage( s, iOpt );
- xbase->WriteLogMessage( "*** End Of Free Blocks ***", iOpt );
- }
-
- pNextPage = pBuf;
- pNextPage+=4;
-
- s = "*** Beginning of Block2 Info ***";
- xbase->WriteLogMessage( s, iOpt );
- s = "ulBlock2 info. ulBlock2 is either one of a linked list of free nodes, or the id of the original node that this node was split from.";
- xbase->WriteLogMessage( s, iOpt );
- s = "Stored in physical file as pages, processed in blocks";
- xbase->WriteLogMessage( s, iOpt );
-
- xbUInt32 ulFirstBlock = 3;
-
- for( xbUInt32 ul = ulFirstBlock; ul < ulLastBlock; ul++ ){
- if(( iRc = ReadBlock( ul, GetBlockSize(), pBuf )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- ulNextPage = eGetUInt32( pNextPage );
- if( ulNextPage > 0 ){
- s.Sprintf( " Block# = %ld\tPage# = %ld\tulBlock2 = %ld\tulBlock2(Page) = %ld", ul, BlockToPage( ul ), PageToBlock( ulNextPage ), ulNextPage );
- xbase->WriteLogMessage( s, iOpt );
- }
- }
- s = "*** End of Block2 Info ***";
- xbase->WriteLogMessage( s, iOpt );
-
- if( pBuf ) free( pBuf );
- }
-
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::DumpFreeBlocks() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- if( pBuf ) free( pBuf );
- }
- return iRc;
-}
-
-/**************************************************************************************************************/
-//! @brief Dump interior and leaf blocks for a given tag.
-/*!
- Dump blocks for given tag for index debugging purposes.
-
- A page is 512 bytes<br>
- A block is one or more pages<br>
- The default mdx block size is 2 pages, or 1024 bytes<br>
- The first four pages or header pages<br>
-
- \param iOpt Output message destination<br>
- 0 = stdout<br>
- 1 = Syslog<br>
- 2 = Both<br>
- \param vpTag Index tag pointer, defaults to all tags if null.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-
-*/
-
-xbInt16 xbIxMdx::DumpTagBlocks( xbInt16 iOpt, void * vpTag ){
-
- xbInt16 iRc = 0;
- xbInt16 iErrorStop = 0;
- xbInt16 iCurTag = 0;
- xbString s;
- xbInt16 iBlockCtr = 0;
-
- try{
-
- xbMdxTag * mpTag;
- if( vpTag == NULL )
- mpTag = (xbMdxTag *) GetTag( iCurTag++ );
- else
- mpTag = (xbMdxTag *) vpTag;
-
- if( mpTag == NULL ){
- iErrorStop = 100;
- iRc = XB_INVALID_TAG;
- throw iRc;
- }
-
- xbIxNode *n;
- xbString s;
- xbString s2;
- xbBool bDone = xbFalse;
-
- xbUInt32 ulBlkNo;
- xbLinkListOrd<xbUInt32> ll;
- xbLinkListNode<xbUInt32> * llN;
-
- ll.SetDupKeys( xbFalse );
-
- s.Sprintf( "%s Root Page %ld (Block %ld)", mpTag->cTagName, mpTag->ulRootPage, PageToBlock( mpTag->ulRootPage ) );
- xbase->WriteLogMessage( s, iOpt );
-
- // for each tag
- while( !bDone ){
-
- // clear out any history
- ll.Clear();
- if( mpTag->npNodeChain ){
- mpTag->npNodeChain = FreeNodeChain( mpTag->npNodeChain );
- mpTag->npCurNode = NULL;
- }
-
- while( GetNextKey( mpTag, 0 ) == 0 ){
- n = mpTag->npNodeChain;
-
- while(n){
- ll.InsertKey( n->ulBlockNo, (xbUInt32) n->iCurKeyNo );
- n = n->npNext;
- }
- }
- llN = ll.GetHeadNode();
-
- while( llN ){
-
- ulBlkNo = llN->GetKey();
- xbIxMdx::DumpBlock( iOpt, ulBlkNo, mpTag );
- llN = llN->GetNextNode();
- iBlockCtr++;
- }
-
- if( vpTag || iCurTag >= GetTagCount())
- bDone = xbTrue;
- else
- mpTag = (xbMdxTag *) GetTag( iCurTag++ );
- }
-
- s.Sprintf( "\nTotal Blocks: %d", iBlockCtr );
- xbase->WriteLogMessage( s, iOpt );
-
- if( mpTag->npNodeChain ){
- mpTag->npNodeChain = FreeNodeChain( mpTag->npNodeChain );
- mpTag->npCurNode = NULL;
- }
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::DumpTagBlocks() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- 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>
- \param iFmtOpt Output Format<br>
- 0, 1 = Header info only<br>
- 2 = Tag info<br>
- 3 = Header && Tag info<br>
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-xbInt16 xbIxMdx::DumpHeader( xbInt16 iOpt, xbInt16 iFmtOpt )
-{
-
- xbInt16 iRc = XB_NO_ERROR;
- xbString s;
- if(( iRc = ReadHeadBlock( 1 )) != XB_NO_ERROR )
- return iRc;
-
-// std::cout << "xbIxMdx::DumpHeader options - " << iDestOpt << " fmtopt = " << iFmtOpt << "\n";
-
- char c, tfv, cDisplayMask = 1;
- cDisplayMask = cDisplayMask << 7;
- if( iFmtOpt != 2 && iFmtOpt != 4 ){
- s = "*** MDX Index Header ***";
- xbase->WriteLogMessage( s, iOpt );
- s = "Version = ";
- tfv = cVersion;
- for( c = 1; c<= 8; c++ ){
- //std::cout << (tfv & cDisplayMask ? '1' : '0');
- s+= (tfv & cDisplayMask ? '1' : '0');
- tfv <<= 1;
- }
- xbase->WriteLogMessage( s, iOpt );
-
-
-// std::cout << std::endl;
-// std::cout <<
- s.Sprintf( "Create Date = %d/%d/%d", (int) cCreateMM, (int) cCreateDD, (int) cCreateYY % 100 );
- xbase->WriteLogMessage( s, iOpt );
-
- s.Sprintf( "File Name = %s", sFileName.Str() );
- xbase->WriteLogMessage( s, iOpt );
-
- s.Sprintf( "Block Factor = %d", iBlockFactor );
- xbase->WriteLogMessage( s, iOpt );
-
- s.Sprintf( "Block Size = %d", GetBlockSize() );
- xbase->WriteLogMessage( s, iOpt );
-
- s.Sprintf( "Prod Ix Flag = %d", (xbInt16) cProdIxFlag );
- xbase->WriteLogMessage( s, iOpt );
-
- s.Sprintf( "Tag Entry Cnt = %d", (xbInt16) cTagEntryCnt );
- xbase->WriteLogMessage( s, iOpt );
-
- s.Sprintf( "Tag Len = %d", iTagLen );
- xbase->WriteLogMessage( s, iOpt );
-
- s.Sprintf( "Next Tag = %d", (xbInt16) cNextTag );
- xbase->WriteLogMessage( s, iOpt );
-
- s.Sprintf( "Tag Use Cnt = %d", iTagUseCnt );
- xbase->WriteLogMessage( s, iOpt );
-
- s.Sprintf( "Page Cnt = %d", ulPageCnt );
- xbase->WriteLogMessage( s, iOpt );
-
- s.Sprintf( "First Free Page = %d", ulFirstFreePage );
- xbase->WriteLogMessage( s, iOpt );
-
- s.Sprintf( "No Of Block Avail = %d\n", ulNoOfBlockAvail );
- xbase->WriteLogMessage( s, iOpt );
-
- s.Sprintf( "Last update date = %d/%d/%d", (int) cCreateMM, (int) cCreateDD, (int) cCreateYY % 100 );
- xbase->WriteLogMessage( s, iOpt );
-
- if( ulFirstFreePage > 0 ){
- xbString s;
- xbUInt32 ulNfp = ulFirstFreePage; // next free page
- xbInt16 lc = 0;
- while( ulNfp && lc++ < 5 ){
- if( s.Len() > 0 )
- s += ",";
- s.Sprintf( "%s%ld", s.Str(), ulNfp );
- if(( iRc = GetBlock( NULL, (xbUInt32) (ulNfp / (xbUInt32) iBlockFactor), 0 )) != 0 )
- return iRc;
- ulNfp = eGetUInt32( cNodeBuf+4 );
- }
- xbase->WriteLogMessage( s, iOpt );
- }
- }
- if( iFmtOpt > 1 ){
- xbMdxTag *tt = mdxTagTbl;
- xbString s;
- xbInt16 i = 0;
-
- if( tt ){
- while( tt ){
- i++;
- if(( iRc = LoadTagDetail( 2, tt )) != XB_NO_ERROR )
- return iRc;
-
- s.Sprintf( "TTE (%d)\tName HdrPage\tFormat\tLeftChild\tRightChild\tParent\tKeyType", i );
- xbase->WriteLogMessage( s, iOpt );
- s.Sprintf( "TTE (%d)\t%-12s %d\t\t%d\t%d\t\t%d\t\t%d\t%c\n", i, tt->cTagName, tt->ulTagHdrPageNo, tt->cKeyFmt, tt->cLeftChild, tt->cRightChild, tt->cParent, tt->cKeyType );
- xbase->WriteLogMessage( s, iOpt );
-
- s.Sprintf( "TTH (%d)\tRoot\tTagSize\tKeyFmt2\tType2\tKeyLen\tKeysPerBlock\tSecType\tKeyItemLen\tSerial#\tHasKeys\tFilter\tDesc\tUnique\tLchild\tRchild\tKeyFmt3\tTagDate", i );
- xbase->WriteLogMessage( s, iOpt );
-
- s.Sprintf( "TTH (%d)\t%d\t%d\t%d\t%c\t%d\t%d\t\t%d\t%d\t\t%x\t%x\t%d\t%d\t%d\t%d\t%d\t%d\t%d/%d/%d",
- i, tt->ulRootPage, tt->ulTagSize, tt->cKeyFmt2, tt->cKeyType2, tt->iKeyLen, tt->iKeysPerBlock, tt->iSecKeyType, tt->iKeyItemLen, tt->cSerialNo, tt->cHasKeys, tt->cHasFilter,
- (((tt->cKeyFmt2 & 0x08) > 0) ? 1 : 0), // descending?
- tt->cUnique, tt->ulLeftChild, tt->ulRightChild, tt->cKeyFmt3, (int) tt->cTagMM, (int) tt->cTagDD, (int) tt->cTagYY % 100 );
-
- xbase->WriteLogMessage( s, iOpt );
-
- s.Sprintf( "Key (%d) %s", i, tt->sKeyExp->Str());
- xbase->WriteLogMessage( s, iOpt );
-
- if( tt->cHasFilter ){
- s.Sprintf( "Flt (%d) %s", i, tt->sFiltExp->Str());
- xbase->WriteLogMessage( s, iOpt );
- }
- xbase->WriteLogMessage( "", iOpt );
- tt = tt->next;
-
- }
- }
- }
- return iRc;
-}
-
-/***********************************************************************/
-xbInt16 xbIxMdx::DumpIxForTag( void *vpTag, xbInt16 iOutputOpt )
-{
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbInt16 iDepth = 0;
- xbUInt32 lKeyCtr = 0;
- xbInt32 iMinDepth = 999999;
- xbInt32 iMaxDepth = 0;
-
- try{
- /*
- get first node
- while interior node
- print the left key
- level++
- go down one on the left
- */
-
- xbMdxTag * mpTag = (xbMdxTag *) vpTag;
- if( mpTag->npNodeChain ){
- mpTag->npNodeChain = FreeNodeChain( mpTag->npNodeChain );
- mpTag->npCurNode = NULL;
- }
-
- // Get the root
- if(( iRc = LoadTagDetail( 2, mpTag )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- // lRootBlock is now available
- if(( iRc = GetBlock( vpTag, (mpTag->ulRootPage / (xbUInt32) iBlockFactor), 1 )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- // if no keys on this node, then the index is empty
- xbUInt32 ulKeyPtr = eGetUInt32( mpTag->npCurNode->cpBlockData );
- if( ulKeyPtr == 0 ){
- iErrorStop = 120;
- iRc = XB_EMPTY;
- throw iRc;
- }
- while( !IsLeaf( vpTag, mpTag->npCurNode )){ // go down the chain looking for a leaf node
- PrintKey( vpTag, mpTag->npCurNode , 0, iDepth++, 'I', iOutputOpt );
- if(( iRc = GetKeyPtr( vpTag, 0, mpTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- if(( iRc = GetBlock( vpTag, (ulKeyPtr / (xbUInt32) iBlockFactor), 1 )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
- }
- if(( iRc = GetKeyPtr( vpTag, 0, mpTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
- // loop through the leaf entries of left most leaf
- if( iDepth < iMinDepth ) iMinDepth = iDepth;
- if( iDepth > iMaxDepth ) iMaxDepth = iDepth;
- xbUInt32 ulNoOfKeys = eGetUInt32( mpTag->npCurNode->cpBlockData );
- for( xbUInt32 ul = 0; ul < ulNoOfKeys; ul++ ){
- PrintKey( vpTag, mpTag->npCurNode , ul, iDepth, 'L', iOutputOpt );
- lKeyCtr++;
- }
-
- // if head node = start node, return
- if( mpTag->npCurNode->ulBlockNo == ( mpTag->ulRootPage / (xbUInt32) iBlockFactor ))
- return XB_NO_ERROR;
-
- xbBool bEof = false;
- while( !bEof ){
-
- // go up the chain, looking for an interior node with more keys on it
- xbIxNode * TempIxNode = mpTag->npCurNode;
- mpTag->npCurNode = mpTag->npCurNode->npPrev;
- mpTag->npCurNode->npNext = NULL;
- TempIxNode->npPrev = NULL;
- TempIxNode = FreeNodeChain( TempIxNode );
- iDepth--;
-
- while( mpTag->npCurNode->iCurKeyNo >= eGetUInt32( mpTag->npCurNode->cpBlockData ) &&
- mpTag->npCurNode->ulBlockNo != ( mpTag->ulRootPage / (xbUInt32) iBlockFactor) ){
- TempIxNode = mpTag->npCurNode;
- mpTag->npCurNode = mpTag->npCurNode->npPrev;
- mpTag->npCurNode->npNext = NULL;
- TempIxNode->npPrev = NULL;
- TempIxNode = FreeNodeChain( TempIxNode );
- iDepth--;
- }
- // if head node && right most key, return
- if( mpTag->npCurNode->ulBlockNo == (mpTag->ulRootPage / (xbUInt32) iBlockFactor) &&
- mpTag->npCurNode->iCurKeyNo == eGetUInt32( mpTag->npCurNode->cpBlockData ))
- bEof = true;
-
- if( !bEof ){
- mpTag->npCurNode->iCurKeyNo++;
- if(( iRc = GetKeyPtr( vpTag, mpTag->npCurNode->iCurKeyNo, mpTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 160;
- throw iRc;
- }
- PrintKey( vpTag, mpTag->npCurNode , mpTag->npCurNode->iCurKeyNo, iDepth++, 'I', iOutputOpt );
-
- if(( iRc = GetBlock( vpTag, (ulKeyPtr / (xbUInt32) iBlockFactor), 1 )) != XB_NO_ERROR ){
- iErrorStop = 170;
- throw iRc;
- }
-
- // traverse down the left side of the tree
- while( !IsLeaf( vpTag, mpTag->npCurNode )) // go down the chain looking for a leaf node
- {
- PrintKey( vpTag, mpTag->npCurNode , 0, iDepth++, 'I', iOutputOpt );
- if(( iRc = GetKeyPtr( vpTag, 0, mpTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 180;
- throw iRc;
- }
- if(( iRc = GetBlock( vpTag, (ulKeyPtr / (xbUInt32) iBlockFactor), 1 )) != XB_NO_ERROR ){
- iErrorStop = 190;
- throw iRc;
- }
- }
- if( iDepth < iMinDepth ) iMinDepth = iDepth;
- if( iDepth > iMaxDepth ) iMaxDepth = iDepth;
- ulNoOfKeys = eGetUInt32( mpTag->npCurNode->cpBlockData );
- for( xbUInt32 ul = 0; ul < ulNoOfKeys; ul++ ){
- PrintKey( vpTag, mpTag->npCurNode , ul, iDepth, 'L', iOutputOpt );
- lKeyCtr++;
- }
- }
- }
- xbString s;
- s.Sprintf( "Total keys = [%ld] Min Depth = [%d] Max Depth = [%d]", lKeyCtr, iMinDepth, iMaxDepth );
- xbase->WriteLogMessage( s.Str(), 2 );
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::DumpIxForTag() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-/**************************************************************************************************************/
-void xbIxMdx::DumpIxNodeChain( void *vpTag, xbInt16 iOutputOpt ) const
-{
- xbMdxTag * mpTag = (xbMdxTag *) vpTag;
- xbString s( "Dump Node Chain" );
- xbase->WriteLogMessage( s, 2 );
-
- if( mpTag->npNodeChain ){
- xbIxNode *n = mpTag->npNodeChain;
- xbInt16 iCtr = 0;
- char cLeaf;
- s.Sprintf( "Cnt\tThis Prev Next CurKeyNo BlockNo Page NoOfKeys Type" );
- xbase->WriteLogMessage( s, iOutputOpt );
- while( n ){
- IsLeaf( vpTag, n ) ? cLeaf = 'L' : cLeaf = 'I';
- s.Sprintf( "%d\t%08x %08x %08x %08d %08d %08d %08ld %c",
- iCtr++, n, n->npPrev, n->npNext, n->iCurKeyNo,
- n->ulBlockNo, n->ulBlockNo * (xbUInt32) iBlockFactor,
- eGetUInt32( n->cpBlockData ), cLeaf );
- xbase->WriteLogMessage( s, 2 );
- n = n->npNext;
- }
- } else {
- s = "Empty Node Chain";
- xbase->WriteLogMessage( s, 2 );
- }
-}
-#endif
-
-/***********************************************************************************************/
-xbInt16 xbIxMdx::FindKey( void *vpTag, xbDouble dKey, xbInt16 iRetrieveSw ){
-
- xbMdxTag * mpTag = (xbMdxTag *) vpTag;
- if( mpTag->cKeyType2 == 'N' ){ // mdx indices store numeric keys as bcd values
- xbBcd bcd( dKey );
- return xbIx::FindKey( vpTag, bcd, iRetrieveSw );
- } else // this would be a julian date inquiry
- return FindKey( vpTag, &dKey, 8, iRetrieveSw );
-}
-
-/***********************************************************************************************/
-// iRetrieveSw = 1 - position db file to index position
-// 0 - do not position dbf file
-
-xbInt16 xbIxMdx::FindKey( void *vpTag, const void * vpKey,
- xbInt32 lSearchKeyLen, xbInt16 iRetrieveSw ){
-
- xbInt16 iRc = 0;
- xbInt16 iErrorStop = 0;
-
- 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;
- xbMdxTag * mpTag = (xbMdxTag *) vpTag;
- char cKeyType = GetKeyType( vpTag );
- xbBool bDescending = mpTag->cKeyFmt2 & 0x08;
-
- if( mpTag->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( mpTag->tNodeChainTs < tFileTs ){
- mpTag->npNodeChain = FreeNodeChain( mpTag->npNodeChain );
- mpTag->npCurNode = NULL;
-
- } else {
- // pop up the chain looking for appropriate starting point
- xbBool bDone = false;
- xbIxNode * TempIxNode;
- while( mpTag->npCurNode && !bDone &&
- (mpTag->npCurNode->ulBlockNo != ( mpTag->ulRootPage / (xbUInt32) iBlockFactor ))){ // not root node
- //if no keys on the node, pop up one
- ulNoOfKeys = eGetUInt32( mpTag->npCurNode->cpBlockData );
- if( ulNoOfKeys == 0 ){
- TempIxNode = mpTag->npCurNode;
- mpTag->npCurNode = mpTag->npCurNode->npPrev;
- TempIxNode = FreeNodeChain( TempIxNode );
-
- } else {
-
- iRc = CompareKey( cKeyType, vpKey, GetKeyData( mpTag->npCurNode, 0, mpTag->iKeyItemLen ), (size_t) lSearchKeyLen );
- if( (!bDescending && iRc <= 0) || (bDescending && iRc >= 0 )){
- TempIxNode = mpTag->npCurNode;
- mpTag->npCurNode = mpTag->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( mpTag->npCurNode->cpBlockData ) - 1; // IsLeaf( vpTag, mpTag->npCurNode );
- iRc = CompareKey( cKeyType, vpKey, GetKeyData( mpTag->npCurNode, ulKeyCtr, mpTag->iKeyItemLen), (size_t) lSearchKeyLen );
-
- if( (!bDescending && iRc > 0) || (bDescending && iRc < 0 )){
- TempIxNode = mpTag->npCurNode;
- mpTag->npCurNode = mpTag->npCurNode->npPrev;
- TempIxNode = FreeNodeChain( TempIxNode );
- } else {
- bDone = true;
- }
- }
- }
- }
- }
- }
-
- // either started empty, or cleared due to file time diff
- if( !mpTag->npNodeChain ){
- // Get the root
- if(( iRc = LoadTagDetail( 2, mpTag )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- // lRootBlock is now available
- if(( iRc = GetBlock( vpTag, (mpTag->ulRootPage / (xbUInt32) iBlockFactor), 1 )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
- // if this is a leaf node and no keys on this node, then the index is empty
- ulNoOfKeys = eGetUInt32( mpTag->npCurNode->cpBlockData );
- if( ulNoOfKeys == 0 && IsLeaf( vpTag, mpTag->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( vpTag && !IsLeaf( vpTag, mpTag->npCurNode ) ){
- // get the number of keys on the block and compare the key to the rightmost key
- ulNoOfKeys = eGetUInt32( mpTag->npCurNode->cpBlockData );
-
- if( ulNoOfKeys == 0 ){
- mpTag->npCurNode->iCurKeyNo = 0;
-
- } else {
-
- iRc = CompareKey( cKeyType, vpKey, GetKeyData( mpTag->npCurNode, ulNoOfKeys - 1, mpTag->iKeyItemLen), (size_t) lSearchKeyLen );
- if( (!bDescending && iRc > 0) || (bDescending && iRc < 0)){
- mpTag->npCurNode->iCurKeyNo = ulNoOfKeys;
- }
- else
- {
- mpTag->npCurNode->iCurKeyNo = (xbUInt32) BSearchBlock( cKeyType, mpTag->npCurNode,
- (xbInt32) mpTag->iKeyItemLen, vpKey, (xbInt32) lSearchKeyLen, iSearchRc, bDescending );
- }
- }
-
- if(( iRc = GetKeyPtr( vpTag, mpTag->npCurNode->iCurKeyNo, mpTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
-
- if(( iRc = GetBlock( vpTag, (ulKeyPtr / (xbUInt32)iBlockFactor), 1 )) != XB_NO_ERROR ){
- iErrorStop = 160;
- throw iRc;
- }
- }
-
- ulNoOfKeys = eGetUInt32( mpTag->npCurNode->cpBlockData );
- xbInt16 iCompRc = 0;
-
- if( ulNoOfKeys == 0 ){
- // iCompRc = -1;
- // iRc = XB_EMPTY;
- iRc = XB_NOT_FOUND;
- return iRc;
-
- } else {
-
- iRc = BSearchBlock( cKeyType, mpTag->npCurNode, mpTag->iKeyItemLen, vpKey, lSearchKeyLen, iCompRc, bDescending );
- // iCompRc
- // 0 found
- // < 0 eof encountered, search key > last key in file
- // > 0 not found, positioned to next key
-
- if( iCompRc >= 0 ){
- mpTag->npCurNode->iCurKeyNo = (xbUInt32) iRc;
-
-
- if( iRetrieveSw ){
-
- xbUInt32 ulKey = mpTag->npCurNode->iCurKeyNo;
- if( ulKey >= ulNoOfKeys ) // if position past end of keys, need to go back one and position to last key
- ulKey--;
-
- // if(( iRc = GetKeyPtr( vpTag, mpTag->npCurNode->iCurKeyNo, mpTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
-
- if(( iRc = GetKeyPtr( vpTag, ulKey, mpTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 170;
- throw iRc;
- }
- if(( iRc = dbf->GetRecord( ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 180;
- 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( "xbIxMdx::FindKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/***********************************************************************/
-xbInt16 xbIxMdx::FindKeyForCurRec( void * vpTag )
-{
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbInt16 i = 0;
-
- try{
- if(( iRc = CreateKey( vpTag, 0 )) < XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::FindKeyForCurRec() Exception Caught. Error Stop = [%d] iRc = [%d] Tag=[%d]", iErrorStop, iRc, i );
- 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 xbIxMdx::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
-
- xbMdxTag * mpTag = (xbMdxTag *) vpTag;
- char *p = ( np->cpBlockData);
- p += (8 + (iKeyNo * mpTag->iKeyItemLen));
- ulDbfPtr = eGetUInt32 ( p );
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::GetDbfPtr() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/***********************************************************************/
-/*!
- \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 xbIxMdx::GetFirstKey( void *vpTag, xbInt16 iRetrieveSw = 0 ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
-
- // convert the tag pointer to mdx tag pointer
- xbMdxTag * mpTag = (xbMdxTag *) vpTag;
-
-
- try{
- // clear out any history
- if( mpTag->npNodeChain ){
- mpTag->npNodeChain = FreeNodeChain( mpTag->npNodeChain );
- mpTag->npCurNode = NULL;
- }
- // Get the root
- if(( iRc = LoadTagDetail( 2, mpTag )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
-
- // lRootPage is available
- if(( iRc = GetBlock( vpTag, (mpTag->ulRootPage / (xbUInt32) iBlockFactor), 1 )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
-
- // if no keys on this node, then the index is empty
- // this is not true
-
- xbUInt32 ulKeyPtr = eGetUInt32( mpTag->npCurNode->cpBlockData );
- if( ulKeyPtr == 0 && IsLeaf( vpTag, mpTag->npCurNode )){
- iRc = XB_EMPTY;
- return iRc;
- }
-
- while( !IsLeaf( vpTag, mpTag->npCurNode )){ // go down the chain looking for a leaf node
- if(( iRc = GetKeyPtr( vpTag, 0, mpTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
-
- if(( iRc = GetBlock( vpTag, (ulKeyPtr / (xbUInt32) iBlockFactor), 1 )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- }
-
- // retrieve record to data buf
- if( iRetrieveSw ){
- if(( iRc = GetKeyPtr( vpTag, 0, mpTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
- if(( iRc = dbf->GetRecord( ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
- }
- // else {
- // throw iRc;
- // }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::GetFirstKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/***********************************************************************/
-//xbBool xbIxMdx::GetIndexUpdated() const {
-// std::cout << "xbIxMdx::GetIndexUpdate() FIX ME \n";
-// return xbFalse;
-//}
-
-/***********************************************************************/
-//! @brief Get the key expression for the given tag.
-/*!
- \param vpTag Tag to retrieve key expression from tag.
- \returns Key expression.
-*/
-
-xbString &xbIxMdx::GetKeyExpression( const void * vpTag ) const{
- xbMdxTag *mpTag = (xbMdxTag *) vpTag;
- return *mpTag->sKeyExp;
-}
-
-/***********************************************************************/
-//! @brief Get the key expression for the given tag.
-/*!
- \param vpTag Tag to retrieve filter expression from tag (if it exists).
- \returns Key filter.
-*/
-
-xbString &xbIxMdx::GetKeyFilter( const void * vpTag ) const{
-
- xbMdxTag * mpTag = (xbMdxTag *) vpTag;
-
- // std::cout << "GetKeyFilter() ";
- if( mpTag->sFiltExp )
- return *mpTag->sFiltExp;
-// std::cout << " not null\n";
- else
- return sNullString;
- // std::cout << " null\n";
-
-// next line causes seg faults
-// return *mpTag->sFiltExp;
-
-}
-/**************************************************************************************************/
-xbInt16 xbIxMdx::GetKeyPtr( void *vpTag, xbInt16 iKeyNo, xbIxNode *np, xbUInt32 &ulKeyPtr ) const {
-
- xbInt16 iRc = XB_NO_ERROR;
-
- xbInt16 iErrorStop = 0;
-
- try{
-
- xbMdxTag *mdxTag = (xbMdxTag *) vpTag;
- char *p = np->cpBlockData;
- xbUInt32 ulKeyCnt = eGetUInt32( p );
- if( iKeyNo < 0 || iKeyNo > (xbInt16) ulKeyCnt ){
- iErrorStop = 100;
- iRc = XB_INVALID_KEYNO;
- throw iRc;
- }
- p+=8; // skip past first two four byte numeric fields
- p+= (iKeyNo * mdxTag->iKeyItemLen);
- ulKeyPtr = eGetUInt32( p );
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::GetKeyPtr() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- 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
-
-*/
-inline xbInt16 xbIxMdx::GetKeySts( void *vpTag ) const{
-
- xbMdxTag *mpTag = (xbMdxTag *) vpTag;
- return mpTag->iKeySts;
-}
-
-/***********************************************************************/
-char xbIxMdx::GetKeyType( const void *vpTag ) const {
- xbMdxTag * mpTag = (xbMdxTag *) vpTag;
- return mpTag->cKeyType;
-}
-
-/***********************************************************************/
-//! @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 xbIxMdx::GetLastKey( void *vpTag, xbInt16 iRetrieveSw ){
- return GetLastKey( 0, vpTag, iRetrieveSw );
-}
-
-/***********************************************************************/
-//! @brief Get the last key for the given tag and starting node.
-/*!
- \param ulBlockNo 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 xbIxMdx::GetLastKey( xbUInt32 ulBlockNo, void *vpTag, xbInt16 iRetrieveSw ){
-
- // if UlNodeNo is zero, start at head node, otherwise start at ulNodeNo
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
-
- // convert the tag pointer to mdx tag pointer
- xbMdxTag * mpTag = (xbMdxTag *) vpTag;
-
- try{
- xbUInt32 ulNoOfKeys = 0;
- // clear out any history
- if( mpTag->npNodeChain ){
- mpTag->npNodeChain = FreeNodeChain( mpTag->npNodeChain );
- mpTag->npCurNode = NULL;
- }
- // Get the root
- if( ulBlockNo == 0 ){
- if(( iRc = LoadTagDetail( 2, mpTag )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- //if(( iRc = GetBlock( vpTag, (mpTag->ulRootPage / (xbUInt32) iBlockFactor), 1 )) != XB_NO_ERROR ){
- if(( iRc = GetBlock( vpTag, PageToBlock( mpTag->ulRootPage ), 1 )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
-
- } else {
- if(( iRc = GetBlock( vpTag, ulBlockNo, 1 )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- }
-
- ulNoOfKeys = eGetUInt32( mpTag->npCurNode->cpBlockData );
-
- if( ulNoOfKeys == 0 && IsLeaf( vpTag, mpTag->npCurNode )){
- iRc = XB_EMPTY;
- return iRc;
- }
-
- mpTag->npCurNode->iCurKeyNo = ulNoOfKeys;
- ulNoOfKeys = eGetUInt32( mpTag->npCurNode->cpBlockData );
-
- xbUInt32 ulKeyPtr = 0;
- while( !IsLeaf( vpTag, mpTag->npCurNode )){ // go down the chain looking for a leaf node
- // std::cout << "Considered an interior node\n";
- if(( iRc = GetKeyPtr( vpTag, ulNoOfKeys, mpTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- if(( iRc = GetBlock( vpTag, (ulKeyPtr / (xbUInt32) iBlockFactor), 1 )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
-
- ulNoOfKeys = eGetUInt32( mpTag->npCurNode->cpBlockData );
- mpTag->npCurNode->iCurKeyNo = ulNoOfKeys;
- }
- // leaf node has one fewer keys than the interior node
- mpTag->npCurNode->iCurKeyNo--;
- ulNoOfKeys = eGetUInt32( mpTag->npCurNode->cpBlockData );
-
- // retrieve record to data buf
- if( iRetrieveSw ){
- if(( iRc = GetKeyPtr( vpTag, (ulNoOfKeys-1), mpTag->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( "xbIxMdx::GetLastKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- 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 xbIxMdx::GetLastKeyForBlockNo( void *vpTag, xbUInt32 ulBlockNo, char *cpBuf ){
-
- // returns the last key for a given block number
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
-
- xbMdxTag * npTag = (xbMdxTag *) vpTag;
-
- 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;
- }
- memcpy( cpBuf, GetKeyData( npTag->npCurNode, GetKeyCount( npTag->npCurNode ) - 1, npTag->iKeyItemLen ), (size_t) npTag->iKeyLen );
-
- // free memory
- FreeNodeChain( npTag->npNodeChain );
- npTag->npNodeChain = npSaveNodeChain;
- npTag->npCurNode = npSaveCurNode;
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::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 xbIxMdx::GetNextKey( void * vpTag, xbInt16 iRetrieveSw ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
-
- // convert the tag pointer to mdx tag pointer
- xbMdxTag * mpTag = (xbMdxTag *) vpTag;
-
- try{
- if( !mpTag->npCurNode )
- return GetFirstKey( vpTag, iRetrieveSw );
-
- // more keys on this node?
- xbUInt32 ulKeyPtr;
- if( (eGetUInt32( mpTag->npCurNode->cpBlockData ) - 1) > mpTag->npCurNode->iCurKeyNo ){
- mpTag->npCurNode->iCurKeyNo++;
-
- if(( iRc = GetKeyPtr( vpTag, mpTag->npCurNode->iCurKeyNo, mpTag->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 head node, then at eof
- if( mpTag->npCurNode->ulBlockNo == ( mpTag->ulRootPage / (xbUInt32) iBlockFactor ))
- return XB_EOF;
-
- // This logic assumes that interior nodes have n+1 left node no's where n is the number of keys in the node
- xbIxNode * TempIxNode = mpTag->npCurNode;
- mpTag->npCurNode = mpTag->npCurNode->npPrev;
- TempIxNode = FreeNodeChain( TempIxNode );
-
- // While no more right keys && not head node, pop up one node
- while( mpTag->npCurNode->iCurKeyNo >= eGetUInt32( mpTag->npCurNode->cpBlockData ) &&
- mpTag->npCurNode->ulBlockNo != ( mpTag->ulRootPage / (xbUInt32) iBlockFactor) ){
-
- TempIxNode = mpTag->npCurNode;
- mpTag->npCurNode = mpTag->npCurNode->npPrev;
- TempIxNode = FreeNodeChain( TempIxNode );
- }
-
- // if head node && right most key, return eof
- if( mpTag->npCurNode->ulBlockNo == (mpTag->ulRootPage / (xbUInt32) iBlockFactor) &&
- mpTag->npCurNode->iCurKeyNo == eGetUInt32( mpTag->npCurNode->cpBlockData ))
- return XB_EOF;
-
- // move one to the right
- mpTag->npCurNode->iCurKeyNo++;
- if(( iRc = GetKeyPtr( vpTag, mpTag->npCurNode->iCurKeyNo, mpTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
-
- if(( iRc = GetBlock( vpTag, (ulKeyPtr / (xbUInt32) iBlockFactor), 1 )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
-
- // traverse down the left side of the tree
- while( !IsLeaf( vpTag, mpTag->npCurNode )) // go down the chain looking for a leaf node
- {
- if(( iRc = GetKeyPtr( vpTag, 0, mpTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
- if(( iRc = GetBlock( vpTag, (ulKeyPtr / (xbUInt32) iBlockFactor), 1 )) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
- }
- // retrieve record to data buf
- if( iRetrieveSw ){
- if(( iRc = GetKeyPtr( vpTag, 0, mpTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 160;
- throw iRc;
- }
- if(( iRc = dbf->GetRecord( ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 170;
- throw iRc;
- }
- } else {
- return iRc;
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::GetNextKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- 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 xbIxMdx::GetPrevKey( void * vpTag, xbInt16 iRetrieveSw ){
-
- xbString s;
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
-
- // convert the tag pointer to mdx tag pointer
- xbMdxTag * mpTag = (xbMdxTag *) vpTag;
-
- try{
- if( !mpTag->npCurNode ){
- return GetLastKey( 0, vpTag, iRetrieveSw );
- }
-
- xbUInt32 ulKeyPtr = 0;
- // more keys on this assumed-leaf node?
-
- if( mpTag->npCurNode->iCurKeyNo > 0 ){
- mpTag->npCurNode->iCurKeyNo--;
-
- if(( iRc = GetKeyPtr( vpTag, mpTag->npCurNode->iCurKeyNo, mpTag->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 head node = start node, at eof
- if( mpTag->npCurNode->ulBlockNo == ( mpTag->ulRootPage / (xbUInt32) iBlockFactor ))
- return XB_BOF;
-
- // This logic assumes that interior nodes have n+1 left node no's where n is the number of keys in the node
- xbIxNode * TempIxNode = mpTag->npCurNode;
- mpTag->npCurNode = mpTag->npCurNode->npPrev;
- TempIxNode = FreeNodeChain( TempIxNode );
-
- // While no more left keys && not head node, pop up one node
- while( mpTag->npCurNode->iCurKeyNo == 0 &&
- mpTag->npCurNode->ulBlockNo != ( mpTag->ulRootPage / (xbUInt32) iBlockFactor) ){
- TempIxNode = mpTag->npCurNode;
- mpTag->npCurNode = mpTag->npCurNode->npPrev;
- TempIxNode = FreeNodeChain( TempIxNode );
- }
-
- //if head node && left most key, return bof
- if( mpTag->npCurNode->ulBlockNo == ( mpTag->ulRootPage / (xbUInt32) iBlockFactor) && mpTag->npCurNode->iCurKeyNo == 0 )
- return XB_BOF;
-
- // move one to the left
- mpTag->npCurNode->iCurKeyNo--;
- if(( iRc = GetKeyPtr( vpTag, mpTag->npCurNode->iCurKeyNo, mpTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
-
- if(( iRc = GetBlock( vpTag, (ulKeyPtr / (xbUInt32) iBlockFactor), 1 )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
-
- // traverse down the right side of the tree
- xbUInt32 ulNoOfKeys;
- while( !IsLeaf( vpTag, mpTag->npCurNode )) // go down the chain looking for a leaf node
- {
- ulNoOfKeys = eGetUInt32( mpTag->npCurNode->cpBlockData );
- mpTag->npCurNode->iCurKeyNo = ulNoOfKeys;
-
- if(( iRc = GetKeyPtr( vpTag, ulNoOfKeys, mpTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
- if(( iRc = GetBlock( vpTag, (ulKeyPtr / (xbUInt32) iBlockFactor), 1 )) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
- }
-
- // ulNoOfKeys = eGetUInt32( mpTag->npCurNode->cpBlockData );
- mpTag->npCurNode->iCurKeyNo = eGetUInt32( mpTag->npCurNode->cpBlockData ) - 1;
-
- // retrieve record to data buf
- if( iRetrieveSw ){
- if(( iRc = GetKeyPtr( vpTag, mpTag->npCurNode->iCurKeyNo, mpTag->npCurNode, ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 160;
- throw iRc;
- }
- if(( iRc = dbf->GetRecord( ulKeyPtr )) != XB_NO_ERROR ){
- iErrorStop = 170;
- throw iRc;
- }
- } else {
- return iRc;
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::GetPrevKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/***********************************************************************/
-//! @brief GetReuseEmptyNode swuitch setting.
-/*!
- \returns xbFalse - Do not reuse empty MDX index nodes (Dbase 6. behavior).
- xbTrue - Reuse empty MDX index nodes.
-*/
-
-xbBool xbIxMdx::GetReuseEmptyNodesSw() const {
- return bReuseEmptyNodes;
-}
-/***********************************************************************/
-xbBool xbIxMdx::GetSortOrder( void *vpTag ) const {
-
- // return true if descending
- xbMdxTag *mTag = (xbMdxTag *) vpTag;
- if( mTag->cKeyFmt2 & 0x08 )
- return 0x01;
- else
- return 0x00;
-}
-
-/***********************************************************************/
-//! @brief Get tag for tag number.
-/*!
- \param iTagNo - Zero based, which tag to retrieve.
- \returns Pointer to mdx tag for a given tag number.
-*/
-
-void * xbIxMdx::GetTag( xbInt16 iTagNo ) const {
-
- xbMdxTag *tt = mdxTagTbl;
- xbInt16 i = 0;
-
- while( i < iTagNo && tt->next ){
- tt = tt->next;
- i++;
- }
- if( i == iTagNo )
- return (void *) tt;
- else
- return NULL;
-}
-
-/***********************************************************************/
-//! @brief Get tag for tag name.
-/*!
- \sTagName - Tag name to retrieve.
- \returns Pointer to mdx tag for a given tag number.
-*/
-
-void * xbIxMdx::GetTag( xbString &sTagName ) const {
-
- xbMdxTag *tt = mdxTagTbl;
-
- while( sTagName != tt->cTagName && tt->next ){
- tt = tt->next;
- }
-
- if( sTagName == tt->cTagName )
- return (void *) tt;
- else
- return NULL;
-}
-/***********************************************************************/
-xbInt16 xbIxMdx::GetTagCount() const {
- return iTagUseCnt;
-}
-
-/***********************************************************************/
-void xbIxMdx::GetTagName( void *vpTag, xbString &sTagName ){
-
- xbMdxTag *mpTag = (xbMdxTag *) vpTag;
- sTagName = mpTag->sTagName->Str();
-}
-
-/***********************************************************************/
-//const char *xbIxMdx::GetTagName( void *vpTag, xbInt16 iOpt ) const {
-
-const char *xbIxMdx::GetTagName( void *vpTag, xbInt16 ) const {
- xbMdxTag *mpTag = (xbMdxTag *) vpTag;
- return mpTag->cTagName;
-}
-
-/***********************************************************************/
-xbString &xbIxMdx::GetTagName( void *vpTag ) const {
-
- xbMdxTag *mpTag = (xbMdxTag *) vpTag;
- return *mpTag->sTagName;
-}
-
-/***********************************************************************/
-void *xbIxMdx::GetTagTblPtr() const {
- return (void *) mdxTagTbl;
-}
-
-/***********************************************************************/
-xbBool xbIxMdx::GetUnique( void *vpTag ) const {
-//! @brief Determine unique setting for given tag.
-/*!
- \param vpTag Tag to retrieve expression from.
- \returns xbTrue if unique key.
-*/
- xbMdxTag *mTag = (xbMdxTag *) vpTag;
- return mTag->cUnique;
-}
-
-/***********************************************************************/
-//! @brief Harvest Empty Node.
-/*!
- Harvest empty MDX node and add it to the chain of link nodes
-
- \param mpTag Tag to harvest.
- \param iOpt - 0 Don't write the node info to disk, handled elsewhere (don't write it twice)
- 1 Write the update into to disk
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-xbInt16 xbIxMdx::HarvestEmptyNode( xbMdxTag *mpTag, xbIxNode *npNode, xbInt16 iOpt, xbBool bHarvestRoot ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbBool bRootPage = xbFalse;
- xbInt32 iOffset = 0;
-
- try{
-
-// std::cout << "xbIxMdx::HarvestEmptyNode() page= " << BlockToPage( npNode->ulBlockNo );
-// std::cout << " block = " << npNode->ulBlockNo << "\n";
-
- if( mpTag->ulRootPage == BlockToPage( npNode->ulBlockNo ) && !bHarvestRoot ){
- bRootPage = xbTrue;
-
-// std::cout << "special root page processing *****************\n";
- }
-
- memset( npNode->cpBlockData, 0x00, GetBlockSize());
-
- char *pTrg = npNode->cpBlockData;
- if( !bRootPage ){
- pTrg += 4;
- ePutUInt32( pTrg, ulFirstFreePage );
- }
-
-
- if( bRootPage ){
- if( mpTag->cHasKeys ){
-
- // std::cout << "setting has keys\n";
-
- mpTag->cHasKeys = 0x00;
- if(( iRc = xbFseek( ((mpTag->ulTagHdrPageNo * 512) + 246), SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- if(( iRc = xbFwrite( &mpTag->cHasKeys, 1, 1 )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- // might need to update left sibling and right sibling here.
- // Fields don't seem to be updated consistently by other xbase tools,
- // for now, not updating
-
- }
-
- } else {
-
- // update header
- // seek to position byte 13
- ulFirstFreePage = BlockToPage( npNode->ulBlockNo );
- if(( iRc = xbFseek( 36, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- // write it
- char c4[4];
- ePutUInt32( c4, ulFirstFreePage );
- if(( iRc = xbFwrite( c4, 4, 1 )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
-
- }
-
- if( iOpt == 1 ){
- if(( iRc = xbFseek( (xbInt64) ((npNode->ulBlockNo * GetBlockSize() )) + iOffset, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
- // write out the block
- if(( iRc = xbFwrite( npNode->cpBlockData, GetBlockSize(), 1 )) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
- }
- }
-
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::HarvestEmptyNodeI() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-
-
-/***********************************************************************/
-//! @brief Harvest Tag Nodes.
-/*!
- Save all nodes for a given tag into the free node chain.
- Used for reindexing or deleting a given tag.
-
- \param mpTag Tag for harvesting nodes
- \param bHarvestRoot Set to True when deleting tag
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxMdx::HarvestTagNodes( xbMdxTag *mpTag, xbBool bHarvestRoot ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
-
- xbUInt32 ulBlkNo;
- xbLinkListOrd<xbUInt32> ll;
- xbLinkListNode<xbUInt32> * llN;
- xbIxNode * n;
-
- try{
-
- ll.SetDupKeys( xbFalse );
-
- // clear out any history
- if( mpTag->npNodeChain ){
- mpTag->npNodeChain = FreeNodeChain( mpTag->npNodeChain );
- mpTag->npCurNode = NULL;
- }
-
- while( GetNextKey( mpTag, 0 ) == 0 ){
- n = mpTag->npNodeChain;
- while(n){
- ll.InsertKey( n->ulBlockNo, (xbUInt32) n->iCurKeyNo );
- n = n->npNext;
- }
- }
-
- if( bHarvestRoot )
- ll.InsertKey( PageToBlock( mpTag->ulTagHdrPageNo ), 0 );
-
- llN = ll.GetHeadNode();
- if(( n = xbIx::AllocateIxNode( GetBlockSize())) == NULL ){
- iErrorStop = 100;
- iRc = XB_NO_MEMORY;
- throw iRc;
- }
-
- while( llN ){
- ulBlkNo = llN->GetKey();
-
- // read in a block for the block number
- if(( iRc = ReadBlock( ulBlkNo, GetBlockSize(), n->cpBlockData )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- // harvest it
- n->ulBlockNo = ulBlkNo;
- if(( iRc = HarvestEmptyNode( mpTag, n, 1, bHarvestRoot )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- llN = llN->GetNextNode();
- }
- n = FreeNodeChain( n );
- mpTag->npNodeChain = FreeNodeChain( mpTag->npNodeChain );
- mpTag->npCurNode = NULL;
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::HarvestTagNodes() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/***********************************************************************/
-//! @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 Page number to insert.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxMdx::InsertNodeI( void *vpTag, xbIxNode *npNode, xbInt16 iSlotNo, xbUInt32 ulPtr ){
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- char *pNewKeyPos;
- char *pTrg;
- char *pLastKey = NULL;
- xbMdxTag * npTag;
- npTag = (xbMdxTag *) vpTag;
- xbInt16 iCopyLen;
- xbInt16 iNewKeyPos = 8;
-
-
- try{
-
- xbInt32 lKeyCnt = GetKeyCount( npNode );
- iNewKeyPos += (iSlotNo * npTag->iKeyItemLen);
- char *pSrc = npNode->cpBlockData;
-
- if( iSlotNo < lKeyCnt )
- iCopyLen = ((lKeyCnt - iSlotNo) * npTag->iKeyItemLen) + 4;
- else
- iCopyLen = 0;
-
- xbUInt32 ulRqdBufSize = (xbUInt32) ((lKeyCnt + 1) * npTag->iKeyItemLen) + 12;
- if( ulRqdBufSize > npNode->ulBufSize ){
- npNode->ulBufSize += (xbUInt32) npTag->iKeyItemLen;
- npNode->cpBlockData = (char *) realloc( npNode->cpBlockData, (size_t) npNode->ulBufSize );
- if( !npNode->cpBlockData ){
- iErrorStop = 100;
- iRc = XB_NO_MEMORY;
- throw iRc;
- }
- }
-
- // if not appending to the end of the node, make some room, move things to the right
- pNewKeyPos = npNode->cpBlockData;
- pNewKeyPos += iNewKeyPos;
-
- if( iSlotNo < lKeyCnt ){
- pTrg = pNewKeyPos;
- pTrg += npTag->iKeyItemLen;
- memmove( pTrg, pNewKeyPos, (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 = 110;
- throw iRc;
- }
-
- // get the new right key value for the freshly split node
- pLastKey = (char *) malloc((size_t) npTag->iKeyLen);
- if(( iRc = GetLastKeyForBlockNo( vpTag, PageToBlock( ulKeyPtr2 ), pLastKey )) != XB_NO_ERROR ){
- iRc = 120;
- throw iRc;
- }
-
- // write the key values
- pTrg = pNewKeyPos;
- pTrg += 4;
- pSrc = pLastKey;
- for( xbInt16 i = 0; i < npTag->iKeyLen; i++ )
- *pTrg++ = *pSrc++;
-
- pTrg = pNewKeyPos;
- //pTrg+= npTag->iKeyItemLen - 4;
- pTrg+= npTag->iKeyItemLen;
-
- ePutUInt32( pTrg, ulPtr);
- ePutInt32( npNode->cpBlockData, ++lKeyCnt );
-
- // write out the updated block to disk
- if(( iRc = WriteBlock( npNode->ulBlockNo, GetBlockSize(), npNode->cpBlockData )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- if( pLastKey )
- free( pLastKey );
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::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 xbIxMdx::InsertNodeL( void *vpTag, xbIxNode *npNode, xbInt16 iSlotNo, char * cpKeyBuf, xbUInt32 ulPtr ){
-
- // format of block data is
- // 4 bytes number of keys on block
- // 4 bytes - next free block or split block num
- // repeating
- // 4 bytes record number
- // x bytes key data
-
- // Special processing note: when splitting node, new key is first inserted into full left node before
- // the node is split. This routine will make additional room in the buffer for that scenario
-
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- char *pNewKeyPos; // pointer to position in record for new key composite
- char *pTrg;
-
- xbInt16 iNewKeyPos = 8; // position in data block where new key begins.
- // is the position of the record number, where the fmt is
- // [four byte rec number][actual key data] repeats
-
- xbMdxTag * npTag = (xbMdxTag *) vpTag;
- xbInt16 iCopyLen;
-
- try{
- xbInt32 lKeyCnt = GetKeyCount( npNode );
-
-// std::cout << "InsertNodeL Keycount = " << lKeyCnt << "\n";
-// next line is correct, this aligns with db7
-// "4" is the four byte record number stored to the left of the key
-// xbInt16 iKeyPos = 4 + iSlotNo * npTag->iKeyItemLen;
-
- iNewKeyPos += (iSlotNo * npTag->iKeyItemLen);
-
- // length of number of keys that need to be moved to the right
- if( iSlotNo < lKeyCnt )
- iCopyLen = (lKeyCnt - iSlotNo) * npTag->iKeyItemLen;
- else
- iCopyLen = 0;
-
- // +8 is to include the first two 4 byte fields in the block
- // xbUInt32 ulRqdBufSize = (xbUInt32) (iKeyPos + (npTag->iKeyItemLen * 2) + iCopyLen + 8);
- xbUInt32 ulRqdBufSize = (xbUInt32) ((lKeyCnt + 1) * npTag->iKeyItemLen) + 8;
-
-/*
- std::cout << "InsertNodeL CopyLen = " << iCopyLen << "\n";
- std::cout << "InsertNodeL iNewKeyPos = " << iNewKeyPos << "\n";
- std::cout << "InsertNodeL SlotNo = " << iSlotNo << "\n";
- std::cout << "InsertNodeL lKeyCnt = " << lKeyCnt << "\n";
- std::cout << "InsertNodeL node buf size = " << npNode->ulBufSize << "\n";
- std::cout << "InsertNodeL key item len = " << npTag->iKeyItemLen << "\n";
- std::cout << "InsertNodeL key len = " << npTag->iKeyLen << "\n";
- std::cout << "required buf size = " << ulRqdBufSize << "\n";
- std::cout << "InsertNodeL key buf strlen = " << strlen( npTag->cpKeyBuf ) << "\n";
-*/
-
- if( ulRqdBufSize > npNode->ulBufSize ){
- npNode->ulBufSize += (xbUInt32) npTag->iKeyItemLen;
- npNode->cpBlockData = (char *) realloc( npNode->cpBlockData, (size_t) npNode->ulBufSize );
- if( !npNode->cpBlockData ){
- iErrorStop = 100;
- iRc = XB_NO_MEMORY;
- throw iRc;
- }
- }
-
- // if not appending to end, move things right
-
- pNewKeyPos = npNode->cpBlockData;
- pNewKeyPos += iNewKeyPos;
-
- if( iSlotNo < lKeyCnt ) {
- // pKeyPos = npNode->cpBlockData;
- // pKeyPos += iKeyPos;
- // pKeyPos += iNewKeyPos;
- // pTrg = pKeyPos;
- pTrg = pNewKeyPos;
- pTrg += npTag->iKeyItemLen;
- memmove( pTrg, pNewKeyPos, (size_t) iCopyLen );
-
- }
-
- // write rec number
- ePutUInt32( pNewKeyPos, ulPtr );
-
- // write the key value
- pTrg = pNewKeyPos;
- pTrg += 4;
- char * pSrc = cpKeyBuf;
- for( xbInt16 i = 0; i < npTag->iKeyLen; i++ )
- *pTrg++ = *pSrc++;
-
- // update number of keys on the node
- ePutInt32( npNode->cpBlockData, ++lKeyCnt );
-// std::cout << "lKeyCntA = " << GetKeyCount( npNode ) << "\n";
-
-
- // determine length of node, zap everything to the right of it
- xbUInt32 iStartPos = 8 + ((xbUInt32) lKeyCnt * (xbUInt32) npTag->iKeyItemLen );
- xbUInt32 iClearLen = npNode->ulBufSize - iStartPos;
-
-// std::cout << "InsertNodeL SP = " << iStartPos << " clear len = " << iClearLen << " ulBufsize = " << npNode->ulBufSize << "\n";
- char *p = npNode->cpBlockData;
- p += iStartPos;
- memset( p, 0x00, iClearLen );
-
- // write out the updated block to disk
- if(( iRc = WriteBlock( npNode->ulBlockNo, GetBlockSize(), npNode->cpBlockData )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
-
-// std::cout << "lKeyCntB = " << GetKeyCount( npNode ) << "\n";
-
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::InsertNodeL() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-/***********************************************************************/
-inline xbBool xbIxMdx::IsLeaf( void *vpTag, xbIxNode *npNode ) const{
-
- // for performance reasons, does no data checking
- // will result in potentially hard to find segfaults if passing invalid npNode
-
- xbMdxTag *mTag = (xbMdxTag *) vpTag;
- char *p = npNode->cpBlockData;
-
- xbInt32 lNoOfKeys = eGetInt32( p );
- // mdx interior nodes have a sibling number to the right of the right most key in the node
- p+=8;
- p+= mTag->iKeyItemLen * lNoOfKeys;
-
- // printf( "IsLeaf p = [%d] b1 = [%x] keylen = [%d]\n", eGetUInt32( p ), *p, mTag->iKeyItemLen );
-
- if( eGetUInt32( p ) == 0 ){
- // std::cout << "leaf node\n";
- return true;
- } else {
- // std::cout << "interior node\n";
- return false;
- }
-}
-
-/***********************************************************************/
-xbInt16 xbIxMdx::KeyExists( void * vpTag )
-{
- // this method assumes the key has already been built
-
- xbMdxTag *mpTag = (xbMdxTag *) vpTag;
- xbInt16 iRc = FindKey( vpTag, mpTag->cpKeyBuf, mpTag->iKeyLen, 0 );
-
- // iRc == 0 ? return 1 : return 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 xbIxMdx::KeySetPosAdd( xbMdxTag *mpTag, xbUInt32 ulAddRecNo ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- try{
-
- iRc = FindKey( mpTag, mpTag->cpKeyBuf, mpTag->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( mpTag ) == 0 ){
-
- xbUInt32 ulCurRecNo;
- if(( iRc = GetDbfPtr( mpTag, mpTag->npCurNode->iCurKeyNo, mpTag->npCurNode, ulCurRecNo )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- xbBool bKeysMatch = xbTrue;
-
- while( bKeysMatch && ulAddRecNo > ulCurRecNo && iRc == XB_NO_ERROR ){
- if(( iRc = GetNextKey( mpTag, 0 )) == XB_NO_ERROR ){
- if( memcmp( GetKeyData( mpTag->npCurNode, mpTag->npCurNode->iCurKeyNo, mpTag->iKeyItemLen ), mpTag->cpKeyBuf, (size_t) mpTag->iKeyLen ))
- bKeysMatch = xbFalse;
- else{
- if(( iRc = GetDbfPtr( mpTag, mpTag->npCurNode->iCurKeyNo, mpTag->npCurNode, ulCurRecNo )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- }
- }
- }
- }
- if( iRc == XB_EOF ){ // eof condition
- if(( iRc = GetLastKey( 0, mpTag, 0 )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- mpTag->npCurNode->iCurKeyNo++;
- return XB_NO_ERROR;
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::KeySetPosAdd() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/***********************************************************************/
-//! @brief Set position for key delete.
-/*!
- 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 xbIxMdx::KeySetPosDel( xbMdxTag *npTag ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbString sMsg;
-
- try{
-
- iRc = FindKey( npTag, npTag->cpKeyBuf2, npTag->iKeyLen, 0 );
- if( iRc == XB_NOT_FOUND || iRc == XB_EMPTY )
- return XB_NO_ERROR; // good pos ition
- 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( npTag ) == 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( "xbIxMdx::KeySetPosDel() 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 xbtrue - Key was updated.<br>xbFalse - Key not updated.
-*/
-/*
-inline xbBool xbIxMdx::KeyFiltered( void *vpTag ) const{
-
- xbMdxTag *mpTag = (xbMdxTag *) vpTag;
- return mpTag->bKeyFiltered;
-}
-*/
-/***********************************************************************/
-xbInt16 xbIxMdx::LoadTagDetail( xbInt16 iOption, xbMdxTag *tte ){
-
- // option 1 - Load the entire tag detail
- // option 2 - Load the dynamic variables only
-
- // std::cout << "LoadTagDetail() iOption = " << iOption << "\n";
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- size_t iReadSize;
- char *buf = NULL;
- char *p;
-
- try{
- // set the read length based on the option
- if( iOption == 1 )
- iReadSize = 1024;
-
- else if( iOption == 2 )
- // iReadSize = 4;
- iReadSize = 260;
- else{
- iRc = XB_INVALID_OPTION;
- iErrorStop = 100;
- throw iRc;
- }
- if(( buf = (char *) calloc( 1, (size_t) iReadSize )) == NULL ){
- iErrorStop = 110;
- iRc = XB_NO_MEMORY;
- throw iRc;
- }
- if(( iRc = ReadBlock( tte->ulTagHdrPageNo,(xbUInt32) (GetBlockSize() / (xbUInt16) iBlockFactor),
- iReadSize, buf )) != XB_NO_ERROR ){
- free( buf );
- iErrorStop = 30;
- throw iRc;
- }
-
- p = buf;
- tte->ulRootPage = eGetUInt32( p );
-
- if( iOption == 1 ){
- p+=4;
- tte->ulTagSize = eGetUInt32( p );
- p+=4;
- tte->cKeyFmt2 = *p;
- p++;
- tte->cKeyType2 = *p;
- p+=3;
- tte->iKeyLen = eGetInt16( p );
- p+=2;
- tte->iKeysPerBlock = *p;
- p+=2;
- tte->iSecKeyType = eGetInt16( p );
- p+=2;
- tte->iKeyItemLen = eGetInt16( p );
- p+=2;
- tte->cSerialNo = *p;
- p+=3;
- tte->cUnique = *p;
- p++;
-
- // next line assumes expression is a null terminated string in the block
- tte->sKeyExp = new xbString();
- tte->sKeyExp->Sprintf( "%s", p );
-
- p+=221;
- tte->cHasFilter = *p;
- p+=1;
- tte->cHasKeys = *p;
- p+=2;
- tte->ulLeftChild = eGetUInt32( p );
- p+=4;
- tte->ulRightChild = eGetUInt32( p );
- p+=5;
- tte->cTagYY = *p;
- p++;
- tte->cTagMM = *p;
- p++;
- tte->cTagDD = *p;
- // p+=223;
-
- p+=221;
- tte->cKeyFmt3 = *p;
-
-//for( int i = 0; i < 5; i++ )
-// printf( "%d [%x]\n", i, *p++ );
-// p+=2;
-
- if( tte->cHasFilter ){
- p+=282;
- tte->sFiltExp = new xbString();
- tte->sFiltExp->Sprintf( "%s", p );
- tte->filter = new xbExp( xbase, dbf );
- if(( iRc = tte->filter->ParseExpression( tte->sFiltExp->Str())) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- }
- tte->npNodeChain = NULL;
- tte->npCurNode = NULL;
- tte->cpKeyBuf = (char *) malloc( (size_t) tte->iKeyLen + 1 );
- tte->cpKeyBuf2 = (char *) malloc( (size_t) tte->iKeyLen + 1 );
- tte->exp = new xbExp( xbase, dbf );
- if(( iRc = tte->exp->ParseExpression( tte->sKeyExp->Str() )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- } else if( iOption == 2 ){
- // refresh the dynamic tag variables
- p+=4;
- tte->ulTagSize = eGetUInt32( p );
- p+= 16;
- tte->cSerialNo = *p;
- p+= 226;
- tte->cHasKeys = *p;
- p+=2;
- tte->ulLeftChild = eGetUInt32( p );
- p+=4;
- tte->ulRightChild = eGetUInt32( p );
- p+=5;
- tte->cTagYY = *p;
- p++;
- tte->cTagMM = *p;
- p++;
- tte->cTagDD = *p;
- }
- if( buf )
- free( buf );
-
- }
- catch (xbInt16 iRc ){
- if( buf )
- free( buf );
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::LoadTagDetail() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/***********************************************************************/
-xbInt16 xbIxMdx::LoadTagTable()
-{
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- char * buf = NULL;
-
- //std::cout << "xbIxMdx::LoadTagTable() tag use cnt = " << iTagUseCnt << "\n";
-
- try{
-
- if( iTagUseCnt > 46 ){
- iErrorStop = 100;
- iRc = XB_INVALID_INDEX;
- throw iRc;
- }
-
- xbInt16 iBufSize = (xbInt16) iTagLen * iTagUseCnt;
-
- if(( buf = (char *) malloc( (size_t) iBufSize )) == NULL ){
- iErrorStop = 110;
- iRc = XB_NO_MEMORY;
- throw iRc;
- }
-
- if(( iRc = xbFseek( 544, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
-
- if(( iRc = xbFread( buf, (size_t) iBufSize, 1 )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
-
- xbInt16 iPos;
- char *p;
- xbMdxTag *tte;
- xbMdxTag *ttel = NULL;
-
- for( xbInt16 i = 0; i < iTagUseCnt; i++ ){
- iPos = i * iTagLen;
- p = buf + iPos;
-
- if(( tte = (xbMdxTag *) calloc( 1, (size_t) sizeof( xbMdxTag ))) == NULL ){
- iErrorStop = 140;
- iRc = XB_NO_MEMORY;
- throw iRc;
- }
-
- // set the current tag to the first tag in the table
- if( !vpCurTag )
- xbIx::SetCurTag( (void *) tte );
-
- if( mdxTagTbl )
- ttel->next = tte;
- else
- mdxTagTbl = tte;
- // tte->sKeyExp = new xbString();
-
- ttel = tte;
- tte->next = NULL;
- tte->ulTagHdrPageNo = eGetUInt32( p );
-
- p += 4;
- for( xbUInt32 i = 0; i < 11; i ++ )
- tte->cTagName[i] = *p++;
-
- tte->cTagName[11] = 0x00;
- tte->cKeyFmt = *p++;
- tte->cLeftChild = *p++;
- tte->cRightChild = *p++;
- tte->cParent = *p++;
- tte->c2 = *p++;
- tte->cKeyType = *p;
- tte->sTagName = new xbString();
- tte->sTagName->Set( tte->cTagName );
- tte->sTagName->Trim();
-
- if(( iRc = LoadTagDetail( 1, tte )) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
- }
- if( buf )
- free( buf );
- }
- catch (xbInt16 iRc ){
- if( buf )
- free( buf );
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::LoadTagTable() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- if( iErrorStop == 100 ){
- sMsg.Sprintf( "xbIxMdx::LoadTagTable() Invalid Tag Count: %d", iTagUseCnt );
- xbase->WriteLogMessage( sMsg.Str());
- }
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/**************************************************************************************************************/
-//! @brief Calculate the block number for a given page.
-/*!
- This routine is called by any function needing to calculate the block number for a given page.
- Page numbers are stored internally in the physical file, and the library reads and writes in
- blocks of one or more pages.
-
- Assumes valid data input
-
- \param ulPageNo Page Number
- \returns Calculated block number.
-*/
-
-inline xbUInt32 xbIxMdx::PageToBlock( xbUInt32 ulPageNo ){
- return ulPageNo / (xbUInt32) iBlockFactor;
-}
-
-
-
-/**************************************************************************************************************/
-#ifdef XB_DEBUG_SUPPORT
-xbInt16 xbIxMdx::PrintKey( void *vpTag, xbIxNode *npNode, xbInt16 iKeyNo, xbInt16 iDepth, char cType, xbInt16 iOutputOpt ){
-
- xbString sPre;
- sPre.Sprintf( "%c ", cType );
- for( xbInt16 i = 0; i < iDepth; i++ )
- sPre += "|";
-
- xbString sPost;
- sPost.Sprintf( "\tThisBlock=[%ld] KeyNo=[%d] Depth=[%d]", npNode->ulBlockNo, iKeyNo, iDepth );
-
- xbMdxTag * mpTag = (xbMdxTag *) vpTag;
- char *p = npNode->cpBlockData + (8 + (iKeyNo * mpTag->iKeyItemLen ));
-
- xbString sKeyPtr;
- xbUInt32 ulNoOfKeys = 0;
- if( cType == 'I' ) { // interior
- sKeyPtr.Sprintf( " ptr=[%ld]", eGetUInt32( p ));
- ulNoOfKeys = eGetUInt32( mpTag->npCurNode->cpBlockData );
- }
- else if( cType == 'L' ) // leaf
- sKeyPtr.Sprintf( " rec=[%ld]", eGetUInt32( p ));
- p += 4;
-
- xbString s;
- if(( cType == 'I' && iKeyNo < (xbInt16) ulNoOfKeys) || cType == 'L' ){
- if( mpTag->cKeyType2 == 'C' ){ //CHAR
- for( xbInt32 l = 0; l < (mpTag->iKeyItemLen-4); l++ )
- s += *p++;
-
- } else if( mpTag->cKeyType2 == 'N' ){ // NUMERIC
- xbBcd bcd( p );
- xbString s2;
- bcd.ToString( s2 );
- s += s2;
-
- } else if( mpTag->cKeyType2 == 'D' ){ // DATE
- xbInt32 lDate = (xbInt32) eGetDouble( p );
- xbDate d( lDate );
- //xbString s2;
- //d.JulToDate8( lDate, s2 );
- s.Sprintf( "%s%s", s.Str(), d.Str());
- }
- } else {
- s = "Rightmost InteriorNode Pointer";
- }
-
- xbString sOut( sPre );
- sOut += s;
- sOut += sPost;
- sOut += sKeyPtr;
-
- xbase->WriteLogMessage( sOut, iOutputOpt );
- return XB_NO_ERROR;
-}
-#endif
-
-/***********************************************************************/
-//! @brief ReadHeadBlock.
-/*!
- Read values off head block in MDX file
- \param iOpt 0 - Read entire block, initialize as needed.<br>
- 1 - Read in only dynamic section of block<br>
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-
-*/
-
-xbInt16 xbIxMdx::ReadHeadBlock( xbInt16 iOpt )
-{
-
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
-
-// std::cout << "ReadHeadBlock() option = " << iOpt << "\n";
-
- try{
- if( !FileIsOpen()){
- iRc = XB_NOT_OPEN;
- iErrorStop = 100;
- throw iRc;
- }
- char sBuf[48];
- memset( sBuf, 0x00, 48 );
-
- if( iOpt == 0 ){
- if(( iRc = xbFseek( 0, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
-
- if(( iRc = xbFread( sBuf, 47, 1 )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- } else {
-
- if(( iRc = xbFseek( 28, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
-
- if(( iRc = xbFread( sBuf, 19, 1 )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
- }
-
- char *p = sBuf;
- if( iOpt == 0 ){
- cVersion = *p++;
- cCreateYY = *p++;
- cCreateMM = *p++;
- cCreateDD = *p++;
- sFileName.Assign( p, 1, 16 );
- p+=16;
- iBlockFactor = eGetInt16( p );
- p+=2;
- SetBlockSize( (xbUInt32) eGetInt16( p ));
- p+=2;
- cProdIxFlag = *p++;
- cTagEntryCnt = *p++;
- iTagLen = *p;
- p+=2;
-
- iTagUseCnt = eGetInt16( p );
- //lTagUseCnt = eGetInt32( p );
- //p+=4;
- p+=2;
- cNextTag = *p++;
- c1B = *p++;
-
- ulPageCnt = eGetUInt32( p );
- p+=4;
- ulFirstFreePage = eGetUInt32( p );
- p+=4;
- ulNoOfBlockAvail = eGetUInt32( p );
- p+=4;
- cUpdateYY = *p++;
- cUpdateMM = *p++;
- cUpdateDD = *p;
-
- if( cNodeBuf )
- free( cNodeBuf );
-
- if(( cNodeBuf = (char *) malloc( (size_t) GetBlockSize())) == NULL ){
- iErrorStop = 150;
- throw XB_NO_MEMORY;
- }
-
- if(( iRc = xbIxMdx::LoadTagTable()) != XB_NO_ERROR ){
- iErrorStop = 160;
- throw iRc;
- }
-
- } else {
- iTagUseCnt = eGetInt16( p );
- p+=4;
- ulPageCnt = eGetUInt32( p );
- p+=4;
- ulFirstFreePage = eGetUInt32( p );
- p+=4;
- ulNoOfBlockAvail = eGetUInt32( p );
- p+=4;
- cUpdateYY = *p++;
- cUpdateMM = *p++;
- cUpdateDD = *p;
- }
-
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::ReadHeadBlock() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- if( cNodeBuf )
- free( cNodeBuf );
- }
- return iRc;
-}
-
-/***********************************************************************/
-//! @brief Reindex
-/*!
- Reindex specifed tag or all tags
- \param **vpTag &tag - Tag to reindex.<br>
- NULL - Reindex all tags<br>
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-
- If this method fails, the index is left in an undefined state
-
-*/
-
-xbInt16 xbIxMdx::Reindex( void **vpTag ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbMdxTag * mpTag;
- #ifdef XB_LOCKING_SUPPORT
- xbBool bLocked = xbFalse;
- #endif
-
- if( vpTag )
- mpTag = (xbMdxTag *) *vpTag;
- else
- mpTag = NULL;
-
- struct tagInfo{
- xbBool bUnique;
- xbBool bDesc;
- char sTagName[11];
- xbString *sKeyExp;
- xbString *sFiltExp;
- tagInfo *next;
- };
- tagInfo *ti = NULL;
-
- 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
-
- if( mpTag == NULL ){
- // do all tags
- xbMdxTag *tt = mdxTagTbl;
- tagInfo *pHead = NULL;
- tagInfo *pEnd = NULL;
-
- if( tt ){
- while( tt ){
- ti = (tagInfo *) calloc( 1, sizeof( tagInfo ));
- ti->bUnique = tt->cUnique ? 1 : 0;
- ti->bDesc = (((tt->cKeyFmt2 & 0x08) > 0) ? 1 : 0);
- memcpy( ti->sTagName, tt->cTagName, 11 );
- ti->sKeyExp = new xbString( tt->sKeyExp->Str());
- if( tt->cHasFilter )
- ti->sFiltExp = new xbString( tt->sFiltExp->Str());
- else
- ti->sFiltExp = new xbString( "" );
- if( !pHead )
- pHead = ti;
- else
- pEnd->next = ti;
- pEnd = ti;
- tt = tt->next;
- }
- }
-
- // get the file name and save it
- xbString sMdxFileName = GetFqFileName();
-
- // close the mdx file
- if(( iRc = xbIxMdx::Close()) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
-
- // delete the file
- xbRemove();
-
- // init variables
- Init();
-
- tagInfo *p = pHead;
- tagInfo *pDel;
-
- // create new file & add the tags
- while( p ){
-
- //std::cout << "Reindex() linked list extract\n";
- //std::cout << "Tag Name = [" << p->sTagName << "]\n";
- //std::cout << "Key Exp = [" << p->sKeyExp->Str() << "]\n";
- //std::cout << "Filt Exp = [" << p->sFiltExp->Str() << "]\n";
- //std::cout << "bDesc = [" << p->bDesc << "]\n";
- //std::cout << "bUnique = [" << p->bUnique << "]\n";
-
- if(( iRc = CreateTag( p->sTagName, p->sKeyExp->Str(), p->sFiltExp->Str(), p->bDesc, p->bUnique, xbTrue, vpTag )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- delete p->sKeyExp;
- delete p->sFiltExp;
- pDel = p;
- p = p->next;
- free( pDel );
- }
- } else {
- if(( iRc = HarvestTagNodes( mpTag )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- }
-
- xbUInt32 ulRecCnt = 0;
- if(( iRc = dbf->GetRecordCnt( ulRecCnt )) != XB_NO_ERROR ){
- iErrorStop = 140;
- throw iRc;
- }
- xbInt16 iCurTag = 0;
- xbBool bDone = xbFalse;
-
- for( xbUInt32 ulRec = 1; ulRec <= ulRecCnt; ulRec++ ){
- if(( iRc = dbf->GetRecord( ulRec )) != XB_NO_ERROR ){
- iErrorStop = 150;
- throw iRc;
- }
-
- bDone = xbFalse;
- iCurTag = 0;
- if( !vpTag )
- mpTag = (xbMdxTag *) GetTag( iCurTag++ );
-
- while( !bDone ){
- // do the tag things
- // CreateKey
- if(( iRc = CreateKey( mpTag, 1 )) != XB_NO_ERROR ){
- iErrorStop = 160;
- throw iRc;
- }
- if( mpTag->iKeySts == XB_ADD_KEY ){
- if( mpTag->cUnique ){
- if(( iRc = CheckForDupKey( mpTag )) != XB_NO_ERROR ){
- iErrorStop = 170;
- throw iRc;
- }
- }
- if(( iRc = AddKey( mpTag, ulRec )) != XB_NO_ERROR ){
- iErrorStop = 180;
- throw iRc;
- }
- }
- if( vpTag || iCurTag >= GetTagCount())
- bDone = xbTrue;
- else
- mpTag = (xbMdxTag *) GetTag( iCurTag++ );
- }
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::ReIndex() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg.Str() );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
-
- #ifdef XB_LOCKING_SUPPORT
- if( bLocked ){
- dbf->LockTable( XB_UNLOCK );
- }
- #endif
- return iRc;
-}
-
-/***********************************************************************/
-xbInt16 xbIxMdx::SetCurTag( xbString &sTagName ) {
-
- xbMdxTag *tt = (xbMdxTag *) GetTag( sTagName );
- if( tt ){
- xbIx::SetCurTag((void *) tt );
- return XB_NO_ERROR;
- } else
- return XB_INVALID_TAG;
-}
-
-/***********************************************************************/
-xbInt16 xbIxMdx::SetCurTag( xbInt16 iTagNo ) {
-
- xbMdxTag *tt = (xbMdxTag *) GetTag( iTagNo );
- if( tt ){
- xbIx::SetCurTag((void *) tt );
- return XB_NO_ERROR;
- } else
- return XB_INVALID_TAG;
-}
-
-/***********************************************************************/
-//! @brief SetReuseEmptyNode switch setting.
-/*!
- \param bEmptyNodeSw xbFalse - Do not reuse empty MDX index nodes (Dbase 6. behavior).
- xbTrue - Reuse empty MDX index nodes.
-*/
-
-void xbIxMdx::SetReuseEmptyNodesSw( xbBool bEmptyNodesSw ) {
- bReuseEmptyNodes = bEmptyNodesSw;
-}
-
-/***********************************************************************/
-//! @brief Set Tag Pointer.
-/*!
- Set binary tree pointer value. The MDX tags are stored with binary
- tree positions. This routine sets the value in memory.
- \param cPtr L - Left child.<br>
- R - Right child.<br>
- P - Parent.
- \param iWhich - Which tag to update
- \param cVal - Value to set.
- \returns void
-*/
-
-/*
-void xbIxMdx::SetTagPtr( char cPtr, xbInt16 iWhich, char cVal ){
-
- xbMdxTag *mpTag = (xbMdxTag *) GetTag( iWhich );
- if( mpTag ){
- switch( cPtr ){
- case 'L':
- mpTag->cLeftChild = cVal;
- break;
- case 'R':
- mpTag->cRightChild = cVal;
- break;
- case 'P':
- mpTag->cParent = cVal;
- break;
- }
- }
-}
-*/
-
-/***********************************************************************/
-//! @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 xbIxMdx::SplitNodeI( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight, xbInt16 iSlotNo, xbUInt32 ulPtr ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbMdxTag * npTag = (xbMdxTag *) vpTag;
- xbDouble dSplitFactor = .5; // split the nodes 50/50
- xbInt16 iLen;
- char *pSrc;
- char *pTrg;
-
-
- try{
- xbInt32 lKeyCnt = GetKeyCount( npLeft );
- xbInt32 lNewLeftKeyCnt = (xbInt32) ((lKeyCnt + 1) * dSplitFactor);
- xbInt32 lNewRightKeyCnt = lKeyCnt - lNewLeftKeyCnt;
- 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
- pSrc = npLeft->cpBlockData;
- pSrc += 8 + ((lNewLeftKeyCnt+1) * npTag->iKeyItemLen);
- pTrg = npRight->cpBlockData;
- pTrg += 8;
- iLen = (lNewRightKeyCnt * npTag->iKeyItemLen) + 4;
- memmove( pTrg, pSrc, (size_t) iLen );
-
- // eliminate chattle on the right
- iLen = 12 + (lNewLeftKeyCnt * npTag->iKeyItemLen);
- pSrc = npLeft->cpBlockData;
- pSrc += iLen;
- memset( pSrc, 0x00, npLeft->ulBufSize - (xbUInt32) iLen );
-
- // 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( "xbIxMdx::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>
-
- 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 xbIxMdx::SplitNodeL( void *vpTag, xbIxNode * npLeft, xbIxNode *npRight,
- xbInt16 iSlotNo, char * cpKeyBuf, xbUInt32 ulPtr ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbDouble dSplitFactor = .5; // can adjust performance with this number
- xbMdxTag *mpTag = (xbMdxTag *) vpTag;
- xbString sMsg;
-
- xbInt16 iLen;
- char *pSrc;
- char *pTrg;
-
- // std::cout << "In xbIxMdx::SplitNodeL()\n";
- try{
- xbInt32 lKeyCnt = GetKeyCount( npLeft );
- xbInt32 lNewLeftKeyCnt = (xbInt32) ((lKeyCnt + 1) * dSplitFactor) + 1;
- xbInt32 lNewRightKeyCnt = lKeyCnt + 1 - lNewLeftKeyCnt;
-
- 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 += 8 + (lNewLeftKeyCnt * mpTag->iKeyItemLen);
- pTrg = npRight->cpBlockData;
- pTrg += 8;
- iLen = lNewRightKeyCnt * mpTag->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 );
-
- // zero out the next key number so this node is not confused with interior node
- iLen = 8 + (lNewLeftKeyCnt * mpTag->iKeyItemLen);
- pSrc = npLeft->cpBlockData;
- pSrc += iLen;
- memset( pSrc, 0x00, npLeft->ulBufSize - (xbUInt32) iLen );
-
- // 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( "xbIxMdx::SplitNodeL() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-/**************************************************************************************************************/
-//! @brief TagSerialNo.
-/*!
- This routine is used internally for reading or updating the serial number on a given tag when the tag.
-
- \param iOption 1 - Read tag serial number off disk, save in structure<br>
- 2 - Write serial number from memory to disk<br>
- 3 - Read serial number off disk, increment, write updated number to disk<br>
- mpTag - Pointer to tag for serial number update
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-xbInt16 xbIxMdx::TagSerialNo( xbInt16 iOption, xbMdxTag * mpTag ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
-
- try{
-
- xbInt64 lPos = (mpTag->ulTagHdrPageNo * 512) + 20;
-
-// std::cout << "UpdateSerialNo offset = " << lPos << " option = " << iOption << "\n";
-
- if( iOption != 2 ){
- if(( iRc = xbFseek( lPos, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- if(( iRc = xbFgetc( mpTag->cSerialNo )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- }
-
- if( iOption == 3 )
- mpTag->cSerialNo++;
-
- if( iOption != 1 ){
- if(( iRc = xbFseek( lPos, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- if(( iRc = xbFwrite( &mpTag->cSerialNo, 1, 1 )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
- }
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::UpdateSerialNo() 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 xbIxMdx::UpdateTagKey( char cAction, void *vpTag, xbUInt32 ulRecNo ){
-
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- xbMdxTag *npTag = (xbMdxTag *) vpTag;
-
- try{
- // save off any needed fields for updating
- xbUInt32 ulTagSizeSave = npTag->ulTagSize;
- // std::cout << "old size = " << ulTagSizeSave << " new size = " << npTag->ulTagSize << "\n";
- //std::cout << "UpdateTagKey - tag size was updated need to do something here - test \n";
-
-
- if( cAction == 'D' || cAction == 'R' ){
- // std::cout << "UpdateTagKey-delete going to DeleteKey \n";
- if(( iRc = DeleteKey( vpTag )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- //std::cout << "UpdateTagKey-delete back from DeleteKey \n";
- }
-
- if( cAction == 'A' || cAction == 'R' ){
- if(( iRc = AddKey( vpTag, ulRecNo )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- }
- if( ulTagSizeSave != npTag->ulTagSize ){
- if(( iRc = UpdateTagSize( npTag, npTag->ulTagSize )) != XB_NO_ERROR) {
- iErrorStop = 120;
- throw iRc;
- }
- }
- // update the serial number
- if(( iRc = TagSerialNo( 3, npTag )) != XB_NO_ERROR ){
- iErrorStop = 130;
- throw iRc;
- }
-
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::UpdateTagKey() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-/**************************************************************************************************************/
-//! @brief Write head block.
-/*!
- This routine updates the MDX file header and commits changes to disk.
- The file header is considered to be the first 2048 bytes in the file.
-
- \param iOption 0 - Entire 2048 byte header, used for creating a new mdx file.<br>
- 1 - Bytes 28 through 46, used when adding or deleting a tag.<br>
- 2 - Bytes 32 through 46, used after updating keys in the file.
- \returns <a href="xbretcod_8h.html">Return Codes</a>
-*/
-
-
-xbInt16 xbIxMdx::WriteHeadBlock( xbInt16 iOption ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
-
- try{
- xbDate d; // default is system date, today
- cUpdateYY = (char) d.YearOf() - 1900;
- cUpdateMM = (char) d.MonthOf();
- cUpdateDD = (char) d.DayOf( XB_FMT_MONTH );
-
- if( iOption > 0 ){
- char buf[48];
- memset( buf, 0x00, 48 );
- xbUInt32 ulStartPos = 0;
- xbUInt32 ulLen = 0;
-
- if( iOption == 1 ){
- ePutInt16( &buf[28], iTagUseCnt );
- buf[30] = cNextTag;
- buf[31] = 0x1b;
- ulStartPos = 28;
- ulLen = 19;
- } else {
- ulStartPos = 32;
- ulLen = 16;
- }
-
- ePutUInt32( &buf[32], ulPageCnt );
- ePutUInt32( &buf[36], ulFirstFreePage );
- ePutUInt32( &buf[40], ulNoOfBlockAvail );
- buf[44] = cUpdateYY;
- buf[45] = cUpdateMM;
- buf[46] = cUpdateDD;
-
- if(( iRc = xbFseek( ulStartPos, SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
-
- if(( iRc = xbFwrite( &buf[ulStartPos], ulLen, 1 )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
-
- } else if( iOption == 0 ){
- char buf[2048];
- memset( buf, 0x00, 2048 );
-
- buf[0] = cVersion;
- cCreateYY = cUpdateYY;
- cCreateMM = cUpdateMM;
- cCreateDD = cUpdateDD;
- buf[1] = cCreateYY;
- buf[2] = cCreateMM;
- buf[3] = cCreateDD;
-
-
- for( xbUInt32 l = 0; l < sFileName.Len() && l < 10; l++ ){
- buf[l+4] = sFileName[l+1];
- }
-
- ePutInt16( &buf[20], iBlockFactor );
- ePutInt16( &buf[22], (xbInt16) GetBlockSize() );
-
- buf[24] = cProdIxFlag;
- buf[25] = cTagEntryCnt;
- ePutInt16 ( &buf[26], iTagLen );
- ePutInt16 ( &buf[28], iTagUseCnt );
- buf[30] = cNextTag;
- buf[31] = c1B;
- ePutUInt32( &buf[32], ulPageCnt );
- ePutUInt32( &buf[36], ulFirstFreePage );
- ePutUInt32( &buf[40], ulNoOfBlockAvail );
- buf[44] = cUpdateYY;
- buf[45] = cUpdateMM;
- buf[46] = cUpdateDD;
-
- // not sure what the following "1" is for in a sea of zeroes....
- // maybe it's current tag or default tag or something along those lines?
- buf[529] = 0x01;
-
- xbRewind();
- if(( iRc = xbFwrite( buf, 2048, 1 )) != XB_NO_ERROR ){
- iErrorStop = 120;
- throw iRc;
- }
- } else {
- iErrorStop = 130;
- iRc = XB_INVALID_OPTION;
- throw iRc;
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::WriteHeadBlock() Exception Caught. Error Stop = [%d] iRc = [%d] option = [%d]", iErrorStop, iRc, iOption );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-/***********************************************************************/
-xbInt16 xbIxMdx::UpdateTagSize( xbMdxTag *mpTag, xbUInt32 ulTagSz ){
-
- xbInt16 iRc = XB_NO_ERROR;
- xbInt16 iErrorStop = 0;
- char buf[4];
- try{
- ePutUInt32( &buf[0], ulTagSz );
- if(( iRc = xbFseek( (xbInt64) ((mpTag->ulTagHdrPageNo *512 )+ 4), SEEK_SET )) != XB_NO_ERROR ){
- iErrorStop = 100;
- throw iRc;
- }
- if(( iRc = xbFwrite( &buf[0], 4, 1 )) != XB_NO_ERROR ){
- iErrorStop = 110;
- throw iRc;
- }
- }
- catch (xbInt16 iRc ){
- xbString sMsg;
- sMsg.Sprintf( "xbIxMdx::UpdateTagSize() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc );
- xbase->WriteLogMessage( sMsg );
- xbase->WriteLogMessage( GetErrorMessage( iRc ));
- }
- return iRc;
-}
-
-
-/***********************************************************************/
-//void xbIxMdx::TestStub( char *s, void *vpTag ){
-void xbIxMdx::TestStub( char *, void * ){
-}
-/***********************************************************************/
-} /* namespace */
-#endif /* XB_MDX_SUPPORT */
-