diff options
Diffstat (limited to 'xbase64/xbntx.cpp')
-rwxr-xr-x | xbase64/xbntx.cpp | 2604 |
1 files changed, 0 insertions, 2604 deletions
diff --git a/xbase64/xbntx.cpp b/xbase64/xbntx.cpp deleted file mode 100755 index 673aa68..0000000 --- a/xbase64/xbntx.cpp +++ /dev/null @@ -1,2604 +0,0 @@ -/* xbntx.xpp - - Xbase64 project source code - - NTX (Clipper) indexing routines for X-Base - - Copyright (C) 1999 SynXis Corp., Bob Cotton - email - bob@synxis.com - - Copyright (C) 1997,2003 Gary A Kunkel - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - - Contact: - - Email: - - xdb-devel@lists.sourceforge.net - xdb-users@lists.sourceforge.net - - - Regular Mail: - - XBase Support - 149C South Main St - Keller Texas, 76248 - USA -*/ - -#ifdef __GNU LesserG__ - #pragma implementation "xbntx.h" -#endif - -#ifdef __WIN32__ -#include <xbase64/xbwincfg.h> -#else -#include <xbase64/xbconfig.h> -#endif - -#include <xbase64/xbase64.h> - -#ifdef XB_INDEX_NTX - -#ifdef HAVE_IO_H -#include <io.h> -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <ctype.h> -#include <sys/stat.h> - -//#include <xbase64/xbexcept.h> - -/*! \file xbntx.cpp -*/ - -/***********************************************************************/ -//! Short description. -/*! -*/ -/* This routine dumps the node chain to stdout */ -#ifdef XBASE_DEBUG -void xbNtx::DumpNodeChain( void ) -{ - xbNodeLink *n; - std::cout << "*************************" << std::endl; - std::cout << "NodeLinkCtr = " << NodeLinkCtr << std::endl; - std::cout << "Reused = " << ReusedNodeLinks << std::endl; - - n = NodeChain; - while(n){ - std::cout << "xbNodeLink Chain" << n->NodeNo << std::endl; - n = n->NextNode; - } - n = FreeNodeChain; - while(n){ - std::cout << "FreeNodeLink Chain" << n->NodeNo << std::endl; - n = n->NextNode; - } - n = DeleteChain; - while(n){ - std::cout << "DeleteLink Chain" << n->NodeNo << std::endl; - n = n->NextNode; - } -} -#endif -/***********************************************************************/ -//! Short description. -/*! - \param n -*/ -/* This routine returns a chain of one or more index nodes back to the */ -/* free node chain */ - -void xbNtx::ReleaseNodeMemory( xbNodeLink * n, xbBool doFree ) -{ - xbNodeLink *temp; - - if(doFree){ - while(n){ - temp = n->NextNode; - if(n->offsets) - free(n->offsets); - free(n); - n = temp; - } - } else { - if(!FreeNodeChain ) - FreeNodeChain = n; - else { /* put this list at the end */ - temp = FreeNodeChain; - while( temp->NextNode ) - temp = temp->NextNode; - temp->NextNode = n; - } - } -} -/***********************************************************************/ -//! Short description. -/*! -*/ -/* This routine returns a node from the free chain if available, */ -/* otherwise it allocates new memory for the requested node */ - -xbNodeLink * xbNtx::GetNodeMemory( void ) -{ - xbNodeLink * temp; - if( FreeNodeChain ){ - temp = FreeNodeChain; - temp->offsets = FreeNodeChain->offsets; - FreeNodeChain = temp->NextNode; - ReusedNodeLinks++; - memset( temp->Leaf.KeyRecs, 0x00, XB_NTX_NODE_SIZE ); - temp->Leaf.NoOfKeysThisNode = 0; - temp->PrevNode = 0x00; - temp->NextNode = 0x00; - temp->CurKeyNo = 0L; - temp->NodeNo = 0L; - - for (int i = 0; i < HeadNode.KeysPerNode + 1; i++){ - temp->offsets[i] = 2 + ((HeadNode.KeysPerNode + 1) * 2) + (HeadNode.KeySize * i); - } - } else { - temp = (xbNodeLink *) malloc( sizeof( xbNodeLink )); - if(temp==NULL) return NULL; - memset( temp, 0x00, sizeof( xbNodeLink )); - temp->offsets = (xbUShort *)malloc( (HeadNode.KeysPerNode + 1) * sizeof(xbUShort)); - if (temp->offsets==NULL) { - free(temp); - return NULL; - }; - NodeLinkCtr++; - } - return temp; -} -/***********************************************************************/ -//! Short description. -/*! -*/ -#ifdef XBASE_DEBUG -void xbNtx::DumpHdrNode( xbShort Option ) -{ - if( Option == 0 ){ - std::cout << "Signature = " << HeadNode.Signature << std::endl; - std::cout << "Version = " << HeadNode.Version << std::endl; - std::cout << "StartPahe = " << HeadNode.StartNode << std::endl; - std::cout << "UnusedOffset = " << HeadNode.UnusedOffset << std::endl; - std::cout << "KeySize = " << HeadNode.KeySize << std::endl; - std::cout << "KeyLen = " << HeadNode.KeyLen << std::endl; - std::cout << "DecimalCount = " << HeadNode.DecimalCount << std::endl; - std::cout << "KeysPerNode = " << HeadNode.KeysPerNode << std::endl; - std::cout << "HalfKeysPerPage = " << HeadNode.HalfKeysPerNode << std::endl; - std::cout << "KeyExpression = " << HeadNode.KeyExpression << std::endl; - std::cout << "Unique = " << HeadNode.Unique << std::endl; - } else - std::cout << "Print Hdr Node option not implemented yet" << std::endl; -} -#endif -/***********************************************************************/ -//! Constructor -/*! -*/ -xbNtx::xbNtx() : xbIndex() -{ -} -/***********************************************************************/ -//! Constructor -/*! - \param pdbf -*/ -xbNtx::xbNtx( xbDbf * pdbf ) : xbIndex (pdbf) -{ - memset( Node, 0x00, XB_NTX_NODE_SIZE ); - memset( &HeadNode, 0x00, sizeof( NtxHeadNode )); - NodeChain = NULL; -// CloneChain = NULL; - FreeNodeChain = NULL; - DeleteChain = NULL; - CurNode = NULL; - NodeLinkCtr = 0L; - ReusedNodeLinks = 0L; -} -/***********************************************************************/ -//! Destructor -/*! -*/ -xbNtx::~xbNtx() -{ - CloseIndex(); -} -/***********************************************************************/ -//! Short description. -/*! -*/ -xbShort xbNtx::GetHeadNode( void ) -{ - char *p; - if( !IsOpen() ) - return XB_NOT_OPEN; - if( _fseek( indexfp, 0, SEEK_SET )) - return XB_SEEK_ERROR; - if(( fread( Node, XB_NTX_NODE_SIZE, 1, indexfp )) != 1 ) - return XB_READ_ERROR; - - /* load the head node structure */ - p = Node; - HeadNode.Signature = dbf->xbase->GetShort( p ); p += sizeof(xbUShort); - HeadNode.Version = dbf->xbase->GetShort( p ); p += sizeof(xbUShort); - HeadNode.StartNode = dbf->xbase->GetULong( p ); p += sizeof(xbULong); - HeadNode.UnusedOffset = dbf->xbase->GetULong( p ); p += sizeof(xbULong); - HeadNode.KeySize = dbf->xbase->GetShort( p ); p += sizeof(xbUShort); - HeadNode.KeyLen = dbf->xbase->GetShort( p ); p += sizeof(xbUShort); - HeadNode.DecimalCount = dbf->xbase->GetShort( p ); p += sizeof(xbUShort); - HeadNode.KeysPerNode = dbf->xbase->GetShort( p ); p += sizeof(xbUShort); - HeadNode.HalfKeysPerNode = dbf->xbase->GetShort( p ); p += sizeof(xbUShort); - strncpy(HeadNode.KeyExpression, p, 256); p+= 256; -// HeadNode.Unique = *p++; ++ is unused code 8/19/03 - gkunkel - HeadNode.Unique = *p; - - p = HeadNode.KeyExpression; - while (*p){ - *p = toupper(*p); - p++; - } - return 0; -} -/***********************************************************************/ -//! Short description. -/*! - \param NodeNo - \param SetNodeChain -*/ -/* This routine reads a leaf node from disk */ -/* */ -/* If SetNodeChain 2, then the node is not appended to the node chain */ -/* but the CurNode pointer points to the node read */ -/* If SetNodeChain 1, then the node is appended to the node chain */ -/* If SetNodeChain 0, then record is only read to Node memory */ - -xbShort xbNtx::GetLeafNode( xbLong NodeNo, xbShort SetNodeChain ) -{ - xbNodeLink *n; - char *p; - - if( !IsOpen() ) - return XB_NOT_OPEN; - - if( _fseek( indexfp, (xbOffT)NodeNo, SEEK_SET )) - return XB_SEEK_ERROR; - - if(( fread( Node, XB_NTX_NODE_SIZE, 1, indexfp )) != 1 ) - return XB_READ_ERROR; - - if( !SetNodeChain ) return 0; - - if(( n = GetNodeMemory()) == NULL ) - return XB_NO_MEMORY; - - n->NodeNo = NodeNo; - n->CurKeyNo = 0L; - n->NextNode = NULL; - - // The offsets at the head of each leaf are not necessarly in order. - p = Node + 2; - for( int i = 0; i < HeadNode.KeysPerNode + 1; i++){ - n->offsets[i] = dbf->xbase->GetShort( p ); - p += 2; - } - - // Do the edian translation correctly - n->Leaf.NoOfKeysThisNode = dbf->xbase->GetShort( Node ); - memcpy( n->Leaf.KeyRecs, Node, XB_NTX_NODE_SIZE ); - - /* put the node in the chain */ - if( SetNodeChain == 1 ){ - if( NodeChain == NULL ){ /* first one ? */ - NodeChain = n; - CurNode = n; - CurNode->PrevNode = NULL; - } else { - n->PrevNode = CurNode; - CurNode->NextNode = n; - CurNode = n; - } - } - else - CurNode = n; - - return 0; -} -/***********************************************************************/ -//! Short description. -/*! - \param n -*/ -#ifdef XBASE_DEBUG -void xbNtx::DumpNodeRec( xbLong n ) -{ - char *p; - xbShort NoOfKeys; - xbLong LeftBranch, RecNo; - xbShort i,j; - - GetLeafNode( n, 0 ); - NoOfKeys = dbf->xbase->GetShort( Node ); - p = Node + 4; /* go past no of keys */ -std::cout << "-----------------------------------------------" << std::endl; - std::cout << "Node # " << n; - std::cout << "Number of keys = " << NoOfKeys << std::endl; - std::cout << " Key Left Rec Key" << std::endl; - std::cout << "Number Branch Number Data" << std::endl; - - for( i = 0; i < GetKeysPerNode()+1 /*NoOfKeys*/; i++ ){ - LeftBranch = dbf->xbase->GetLong( p ); - p+=4; - RecNo = dbf->xbase->GetLong( p ); - p+=4; - std::cout << i << " " - << LeftBranch << " " - << RecNo << " " << std::endl; - for( j = 0; j < HeadNode.KeyLen; j++ ) std::cout << *p++; - } -} -#endif -/***********************************************************************/ -//! Short description. -/*! - \param RecNo - \param n -*/ -xbLong xbNtx::GetDbfNo( xbShort RecNo, xbNodeLink * n ) -{ - NtxLeafNode *temp; - char *p; - xbUShort itemOffset; - - if( !n ) return 0L; - temp = &n->Leaf; - p = temp->KeyRecs; - if( RecNo < 0 || RecNo > ( temp->NoOfKeysThisNode )) return 0L; - itemOffset = GetItemOffset(RecNo, n, 0); - // ItemOffset is from the beginning of the record. - p += itemOffset; - p += 4; - return( dbf->xbase->GetLong( p )); -} -/***********************************************************************/ -//! Short description. -/*! - \param RecNo - \param n -*/ -xbLong xbNtx::GetLeftNodeNo( xbShort RecNo, xbNodeLink * n ) -{ - NtxLeafNode *temp; - char *p; - xbUShort itemOffset; - - if( !n ) return 0L; - temp = &n->Leaf; - p = temp->KeyRecs; - if( RecNo < 0 || RecNo > temp->NoOfKeysThisNode ) return 0L; - itemOffset = GetItemOffset(RecNo, n, 0); - // ItemOffset is from the beginning of the record. - p += itemOffset; - return( dbf->xbase->GetULong( p )); -} - -/***********************************************************************/ -//! Short description. -/*! - \param RecNo - \param n -*/ -char * xbNtx::GetKeyData( xbShort RecNo, xbNodeLink * n ) -{ - NtxLeafNode *temp; - char *p; - xbUShort itemOffset; - if( !n ) return 0L; - temp = &n->Leaf; - p = temp->KeyRecs; - if( RecNo < 0 || RecNo > ( temp->NoOfKeysThisNode )) return 0L; - itemOffset = GetItemOffset(RecNo, n, 0); - // ItemOffset is from the beginning of the record. - p += itemOffset + 8; - return( p ); -} -/***********************************************************************/ -//! Short description. -/*! - \param RecNo - \param n - \param -*/ -xbUShort -xbNtx::GetItemOffset(xbShort RecNo, xbNodeLink *n, xbShort) { - if( RecNo > (this->HeadNode.KeysPerNode + 1) ){ - std::cout << "RecNo = " << RecNo << std::endl; - std::cout << "this->HeadNode.KeysPerNode = " - << this->HeadNode.KeysPerNode << std::endl; - std::cout << "********************* BUG ***********************" - << std::endl; - // ;-) - exit(1); - } - - return n->offsets[RecNo]; -} - -//! Short description. -/*! - \param pos - \param n -*/ -xbUShort -xbNtx::InsertKeyOffset(xbShort pos, xbNodeLink *n) -{ - xbUShort temp; - - // save the new offset - temp = n->offsets[n->Leaf.NoOfKeysThisNode + 1]; - - for( int i = n->Leaf.NoOfKeysThisNode + 1; i > pos; i-- ){ - n->offsets[i] = n->offsets[i-1]; - } - n->offsets[pos] = temp; - - return n->offsets[pos]; -} - -//! Short description. -/*! - \param pos - \param n -*/ -xbUShort -xbNtx::DeleteKeyOffset(xbShort pos, xbNodeLink *n) -{ - xbUShort temp; - xbShort i; - // save the old offset - temp = n->offsets[pos]; - - for( i = pos; i < n->Leaf.NoOfKeysThisNode; i++ ){ - n->offsets[i] = n->offsets[i+1]; - } - n->offsets[i] = temp; - return n->offsets[i]; -} -/***********************************************************************/ -//! Short description. -/*! -*/ -xbLong xbNtx::GetTotalNodes( void ) -{ -// if( &HeadNode ) -// return HeadNode.TotalNodes; -// else - return 0L; -} -/***********************************************************************/ -//! Short description. -/*! -*/ -xbUShort xbNtx::GetKeysPerNode( void ) -{ - if( &HeadNode ) - return HeadNode.KeysPerNode; - else - return 0L; -} -/***********************************************************************/ -//! Short description. -/*! - \param RetrieveSw -*/ -xbShort xbNtx::GetFirstKey( xbShort RetrieveSw ) -{ -/* This routine returns 0 on success and sets CurDbfRec to the record */ -/* corresponding to the first index pointer */ - - xbLong TempNodeNo; - xbShort rc; - -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// if((rc = LockIndex( XB_LOCK )) != 0) -// return rc; -#endif - - /* initialize the node chain */ - if( NodeChain ){ - ReleaseNodeMemory( NodeChain ); - NodeChain = NULL; - } - - if(( rc = GetHeadNode()) != 0 ){ - CurDbfRec = 0L; -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return rc; - } - - /* get a node and add it to the link */ - - if(( rc = GetLeafNode( HeadNode.StartNode, 1 )) != 0 ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return rc; - } - -/* traverse down the left side of the tree */ - while( GetLeftNodeNo( 0, CurNode )){ - TempNodeNo = GetLeftNodeNo( 0, CurNode ); - if(( rc = GetLeafNode( TempNodeNo, 1 )) != 0 ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - CurDbfRec = 0L; - return rc; - } - CurNode->CurKeyNo = 0; - } - CurDbfRec = GetDbfNo( 0, CurNode ); -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - if( RetrieveSw ) - return dbf->GetRecord( CurDbfRec ); - else - return XB_NO_ERROR; -} -/***********************************************************************/ -//! Short description. -/*! - \param RetrieveSw -*/ -xbShort xbNtx::GetNextKey( xbShort RetrieveSw ) -{ -/* This routine returns 0 on success and sets CurDbfRec to the record */ -/* corresponding to the next index pointer */ - - xbNodeLink * TempNodeLink; - xbLong TempNodeNo; - xbShort rc; - -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) - // if((rc = LockIndex( XB_LOCK )) != 0) - // return rc; -#endif - - if( !IsOpen() ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - CurDbfRec = 0L; - return XB_NOT_OPEN; - } - - if( !CurNode ){ - rc = GetFirstKey( RetrieveSw ); -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return rc; - } - - /* more keys on this node ? */ - if(( CurNode->Leaf.NoOfKeysThisNode -1 ) > CurNode->CurKeyNo ){ - CurNode->CurKeyNo++; - CurDbfRec = GetDbfNo( CurNode->CurKeyNo, CurNode ); -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - if( RetrieveSw ) - return dbf->GetRecord( CurDbfRec ); - else - return XB_NO_ERROR; - } - - /* if head node we are at eof */ - if( CurNode->NodeNo == HeadNode.StartNode ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - 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 */ - /* pop up one node to the interior node level & free the leaf node */ - TempNodeLink = CurNode; - CurNode = CurNode->PrevNode; - CurNode->NextNode = NULL; - ReleaseNodeMemory( TempNodeLink ); - - /* while no more right keys && not head node, pop up one node */ - while(( CurNode->CurKeyNo >= CurNode->Leaf.NoOfKeysThisNode ) && - ( CurNode->NodeNo != HeadNode.StartNode )){ - TempNodeLink = CurNode; - CurNode = CurNode->PrevNode; - CurNode->NextNode = NULL; - ReleaseNodeMemory( TempNodeLink ); - } - - /* if head node && right most key, return end-of-file */ - if(( HeadNode.StartNode == CurNode->NodeNo ) && - ( CurNode->CurKeyNo >= CurNode->Leaf.NoOfKeysThisNode )){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return XB_EOF; - } - - /* move one to the right */ - CurNode->CurKeyNo++; - TempNodeNo = GetLeftNodeNo( CurNode->CurKeyNo, CurNode ); - - if(( rc = GetLeafNode( TempNodeNo, 1 )) != 0 ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return rc; - } - -/* traverse down the left side of the tree */ - while( GetLeftNodeNo( 0, CurNode )){ - TempNodeNo = GetLeftNodeNo( 0, CurNode ); - if(( rc = GetLeafNode( TempNodeNo, 1 )) != 0 ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - CurDbfRec = 0L; - return rc; - } - CurNode->CurKeyNo = 0; - } - CurDbfRec = GetDbfNo( 0, CurNode ); -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - if( RetrieveSw ) - return dbf->GetRecord( CurDbfRec ); - else - return XB_NO_ERROR; -} -/***********************************************************************/ -//! Short description. -/*! - \param NodeNo - \param RetrieveSw -*/ -xbShort xbNtx::GetLastKey( xbLong NodeNo, xbShort RetrieveSw ) -{ -/* This routine returns 0 on success and sets CurDbfRec to the record */ -/* corresponding to the last index pointer */ - -/* If NodeNo = 0, start at head node, otherwise start at NodeNo */ - - xbLong TempNodeNo; - xbShort rc; - -// TODO -// NTX files keep no TotalNode count. -// if( NodeNo < 0 || NodeNo > HeadNode.TotalNodes ) -// return XB_INVALID_NODE_NO; - -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// if((rc = LockIndex( XB_LOCK )) != 0) -// return rc; -#endif - - /* initialize the node chain */ - if( NodeChain ){ - ReleaseNodeMemory( NodeChain ); - NodeChain = NULL; - } - if( NodeNo == 0L ) - if(( rc = GetHeadNode()) != 0 ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - CurDbfRec = 0L; - return rc; - } - - /* get a node and add it to the link */ - if( NodeNo == 0L ){ - if(( rc = GetLeafNode( HeadNode.StartNode, 1 )) != 0 ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK); -#endif - CurDbfRec = 0L; - return rc; - } - } else { - if(( rc = GetLeafNode( NodeNo, 1 )) != 0 ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - CurDbfRec = 0L; - return rc; - } - } - CurNode->CurKeyNo = CurNode->Leaf.NoOfKeysThisNode; - -/* traverse down the right side of the tree */ - while( GetLeftNodeNo( CurNode->Leaf.NoOfKeysThisNode, CurNode )){ - TempNodeNo = GetLeftNodeNo( CurNode->Leaf.NoOfKeysThisNode, CurNode ); - if(( rc = GetLeafNode( TempNodeNo, 1 )) != 0 ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - CurDbfRec = 0L; - return rc; - } - CurNode->CurKeyNo = CurNode->Leaf.NoOfKeysThisNode; - } - CurNode->CurKeyNo--; /* leaf node has one fewer ix recs */ - CurDbfRec = GetDbfNo( CurNode->Leaf.NoOfKeysThisNode-1, CurNode ); -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - if( RetrieveSw ) - return dbf->GetRecord( CurDbfRec ); - else - return XB_NO_ERROR; -} -/***********************************************************************/ -//! Short description. -/*! - \param RetrieveSw -*/ -xbShort xbNtx::GetPrevKey( xbShort RetrieveSw ) -{ -/* This routine returns 0 on success and sets CurDbfRec to the record */ -/* corresponding to the previous index pointer */ - - xbNodeLink * TempNodeLink; - xbLong TempNodeNo; - xbShort rc; - -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// if((rc = LockIndex( XB_LOCK )) != 0) -// return rc; -#endif - - if( !IsOpen() ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - CurDbfRec = 0L; - return XB_NOT_OPEN; - } - - if( !CurNode ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - CurDbfRec = 0L; - return GetFirstKey( RetrieveSw ); - } - - /* more keys on this node ? */ - if( CurNode->CurKeyNo > 0 ){ - CurNode->CurKeyNo--; - CurDbfRec = GetDbfNo( CurNode->CurKeyNo, CurNode ); -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - if( RetrieveSw ) - return dbf->GetRecord( CurDbfRec ); - else - return XB_NO_ERROR; - } - - /* this logic assumes that interior nodes have n+1 left node no's where */ - /* n is the number of keys in the node */ - /* pop up one node to the interior node level & free the leaf node */ - - if( !CurNode->PrevNode ){ /* michael - make sure prev node exists */ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return XB_EOF; - } - - TempNodeLink = CurNode; - CurNode = CurNode->PrevNode; - CurNode->NextNode = NULL; - ReleaseNodeMemory( TempNodeLink ); - - /* while no more left keys && not head node, pop up one node */ - while(( CurNode->CurKeyNo == 0 ) && - ( CurNode->NodeNo != HeadNode.StartNode )){ - TempNodeLink = CurNode; - CurNode = CurNode->PrevNode; - CurNode->NextNode = NULL; - ReleaseNodeMemory( TempNodeLink ); - } - - /* if head node && left most key, return end-of-file */ - if(( HeadNode.StartNode == CurNode->NodeNo ) && - ( CurNode->CurKeyNo == 0 )){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return XB_EOF; - } - - /* move one to the left */ - CurNode->CurKeyNo--; - TempNodeNo = GetLeftNodeNo( CurNode->CurKeyNo, CurNode ); - if(( rc = GetLeafNode( TempNodeNo, 1 )) != 0 ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return rc; - } - - if( GetLeftNodeNo( 0, CurNode )) /* if interior node */ - CurNode->CurKeyNo = CurNode->Leaf.NoOfKeysThisNode; - else /* leaf node */ - CurNode->CurKeyNo = CurNode->Leaf.NoOfKeysThisNode -1; - -/* traverse down the right side of the tree */ - while( GetLeftNodeNo( 0, CurNode )){ /* while interior node */ - TempNodeNo = GetLeftNodeNo( CurNode->Leaf.NoOfKeysThisNode, CurNode ); - if(( rc = GetLeafNode( TempNodeNo, 1 )) != 0 ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - CurDbfRec = 0L; - return rc; - } - if( GetLeftNodeNo( 0, CurNode )) /* if interior node */ - CurNode->CurKeyNo = CurNode->Leaf.NoOfKeysThisNode; - else /* leaf node */ - CurNode->CurKeyNo = CurNode->Leaf.NoOfKeysThisNode -1; - } - CurDbfRec = GetDbfNo( CurNode->Leaf.NoOfKeysThisNode -1, CurNode ); -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - if( RetrieveSw ) - return dbf->GetRecord( CurDbfRec ); - else - return XB_NO_ERROR; -} -/***********************************************************************/ -//! Short description. -/*! - \param Key1 - \param Key2 - \param Klen -*/ -xbShort xbNtx::CompareKey( const char * Key1, const char * Key2, xbShort Klen ) -{ -/* if key1 = key2 --> return 0 */ -/* if key1 > key2 --> return 1 */ -/* if key1 < key2 --> return 2 */ - - const char *k1, *k2; - xbShort i; - - if( Klen > HeadNode.KeyLen ) Klen = HeadNode.KeyLen; - k1 = Key1; - k2 = Key2; - for( i = 0; i < Klen; i++ ){ - if( *k1 > *k2 ) return 1; - if( *k1 < *k2 ) return 2; - k1++; - k2++; - } - return 0; -} -/***********************************************************************/ -//! Short description. -/*! - \param Key1 - \param Key2 -*/ -xbShort xbNtx::CompareKey( const char * Key1, const char * Key2) -{ -/* if key1 = key2 --> return 0 */ -/* if key1 > key2 --> return 1 */ -/* if key1 < key2 --> return 2 */ - - int rc; - rc = strcmp(Key1, Key2); - if( rc < 0 ) - return 2; - else if( rc > 0 ) - return 1; - else - return 0; -} -/***********************************************************************/ -//! Short description. -/*! - \param Tkey - \param -*/ -xbULong xbNtx::GetLeafFromInteriorNode( const char * Tkey, xbShort ) -{ - /* This function scans an interior node for a key and returns the */ - /* correct interior leaf node no */ - - xbShort rc, p; - - /* if Tkey > any keys in node, return right most key */ - p = CurNode->Leaf.NoOfKeysThisNode -1 ; - if( CompareKey( Tkey, GetKeyData( p, CurNode )) == 1 ){ - CurNode->CurKeyNo = CurNode->Leaf.NoOfKeysThisNode; - return GetLeftNodeNo( CurNode->Leaf.NoOfKeysThisNode, CurNode ); - } - - /* otherwise, start at the beginning and scan up */ - p = 0; - while( p < CurNode->Leaf.NoOfKeysThisNode){ - rc = CompareKey( Tkey, GetKeyData( p, CurNode ) ); - if (rc == 2) break; - else if (rc == 0){ - CurNode->CurKeyNo = p; - CurDbfRec = GetDbfNo( p, CurNode ); - return 0; - } - p++; - } - - CurNode->CurKeyNo = p; - return GetLeftNodeNo( p, CurNode ); -} -/***********************************************************************/ -//! Short description. -/*! - \param d -*/ -xbShort xbNtx::KeyExists( xbDouble d ) -{ - char buf[9]; - memset( buf, 0x00, 9 ); - dbf->xbase->PutDouble( buf, d ); - return FindKey( buf, 8, 0 ); -} -/***********************************************************************/ -//! Short description. -/*! - \param d -*/ -xbShort xbNtx::FindKey( xbDouble d ) -{ - char buf[9]; - memset( buf, 0x00, 9 ); - dbf->xbase->PutDouble( buf, d ); - return FindKey( buf, 8, 1 ); -} -/***********************************************************************/ -//! Short description. -/*! - \param Key -*/ -xbShort xbNtx::FindKey( const char * Key ) -{ - return FindKey( Key, strlen( Key ), 1 ); -} -/***********************************************************************/ -//! Short description. -/*! - \param Tkey - \param DbfRec -*/ -xbShort xbNtx::FindKey( const char * Tkey, xbLong DbfRec ) -{ - /* find a key with a specifc xbDbf record number */ - xbShort rc; - xbLong CurDbfRecNo; - xbLong CurNtxDbfNo; - -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// if((rc = LockIndex( XB_LOCK )) != 0) -// return rc; -#endif - - /* if we are already on the correct key, return XB_FOUND */ - if( CurNode ){ - CurDbfRecNo = dbf->GetCurRecNo(); - CurNtxDbfNo = GetDbfNo( CurNode->CurKeyNo, CurNode ); - if( CurDbfRecNo == CurNtxDbfNo ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return XB_FOUND; - } - } - - rc = FindKey( Tkey, HeadNode.KeyLen, 0 ); - - while( rc == 0 || rc == XB_FOUND ){ - if( strncmp( Tkey, GetKeyData( CurNode->CurKeyNo, CurNode ), - HeadNode.KeyLen ) == 0 ){ - if( DbfRec == GetDbfNo( CurNode->CurKeyNo, CurNode )){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) - // LockIndex( XB_UNLOCK ); -#endif - return XB_FOUND; - } else - rc = GetNextKey( 0 ); - } else { -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return XB_NOT_FOUND; - } - } -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return XB_NOT_FOUND; -} -/***********************************************************************/ -//! Short description. -/*! -*/ -xbShort xbNtx::FindKey( void ) -{ - /* if no paramaters given, use KeyBuf */ - return( FindKey( KeyBuf, HeadNode.KeyLen, 0 )); -} -/***********************************************************************/ -//! Short description. -/*! - \param Tkey - \param Klen - \param RetrieveSw -*/ -xbShort xbNtx::FindKey( const char * Tkey, xbShort Klen, xbShort RetrieveSw ) -{ - /* This routine sets the current key to the found key */ - /* if RetrieveSw is true, the method positions the dbf record */ - - xbShort rc,i; - xbLong TempNodeNo; - -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// if((rc = LockIndex( XB_LOCK )) != 0) -// return rc; -#endif - if( NodeChain ){ - ReleaseNodeMemory( NodeChain ); - NodeChain = NULL; - } - - if(( rc = GetHeadNode()) != 0 ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - CurDbfRec = 0L; - return rc; - } - - // If the index is empty - if( HeadNode.StartNode == 0){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return XB_NOT_FOUND; - } - - /* load first node */ - if(( rc = GetLeafNode( HeadNode.StartNode, 1 )) != 0 ){ - CurDbfRec = 0L; -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return rc; - } - - /* traverse down the tree until it hits a leaf */ - while( GetLeftNodeNo( 0, CurNode )){ /* while interior node */ - TempNodeNo = GetLeafFromInteriorNode( Tkey, Klen ); - -#if 1 - // GetLeafFromInteriorNode will return 0 if the key is found on - // an inode. But the leftNodeNo will not be 0. - if (TempNodeNo == 0 && GetLeftNodeNo( 0, CurNode ) != 0){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - if( RetrieveSw ) dbf->GetRecord( CurDbfRec ); - return XB_FOUND; - } -#endif - - if(( rc = GetLeafNode( TempNodeNo, 1 )) != 0 ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - CurDbfRec = 0L; - return rc; - } - } - - /* leaf level */ - for( i = 0; i < CurNode->Leaf.NoOfKeysThisNode; i++ ){ - rc = CompareKey( Tkey, GetKeyData( i, CurNode ) ); - if( rc == 0 ){ - CurNode->CurKeyNo = i; - CurDbfRec = GetDbfNo( i, CurNode ); -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - if( RetrieveSw ) dbf->GetRecord( CurDbfRec ); - return XB_FOUND; - } else if( rc == 2 ) { - CurNode->CurKeyNo = i; - CurDbfRec = GetDbfNo( i, CurNode ); - if( RetrieveSw ) dbf->GetRecord( CurDbfRec ); - // If key is lessthan, without length involved, - // Check to see if the substring match -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - if(CompareKey( Tkey, GetKeyData( i, CurNode ), Klen ) == 0) - return XB_FOUND; - else - return XB_NOT_FOUND; - } - } - CurNode->CurKeyNo = i; - CurDbfRec = GetDbfNo( i, CurNode ); -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - if( RetrieveSw ) dbf->GetRecord( CurDbfRec ); - return XB_NOT_FOUND; -} -/***********************************************************************/ -//! Short description. -/*! -*/ -xbShort xbNtx::CalcKeyLen( void ) -{ - xbShort rc; - xbExpNode * TempNode; - char FieldName[11]; - char Type; - TempNode = IxExp->GetFirstTreeNode(); - - if( !TempNode ) return 0; - if( TempNode->Type == 'd' ) return TempNode->ResultLen; - if( TempNode->Type == 'D' ) { - memset( FieldName, 0x00, 11 ); - memcpy( FieldName, TempNode->NodeText, TempNode->Len ); - Type = dbf->GetFieldType( dbf->GetFieldNo( FieldName )); - if( Type == 'N' || Type == 'F' ) - return TempNode->ResultLen; - } - - if(( rc = IxExp->ProcessExpression()) != XB_NO_ERROR ) - return 0; - - TempNode = (xbExpNode *) IxExp->Pop(); - if( !TempNode ) return 0; - rc = TempNode->DataLen; - -// if( !TempNode->InTree ) dbf->xbase->FreeExpNode( TempNode ); - if( !TempNode->InTree ) delete TempNode; - return rc; -} -/***********************************************************************/ -//! Short description. -/*! - \param IxName - \param Exp - \param Unique - \param Overlay -*/ -xbShort xbNtx::CreateIndex(const char * IxName, const char * Exp, xbShort Unique, xbShort Overlay ) -{ - xbShort i, KeyLen, rc; - - if( IsOpen()) CloseIndex(); - if( strlen( Exp ) > 255 ) return XB_INVALID_KEY_EXPRESSION; - if( dbf->GetDbfStatus() == 0 ) return XB_NOT_OPEN; - - /* Get the index file name and store it in the class */ - SetFileName(IxName); - - /* check if the file already exists */ - if(((indexfp = fopen( GetFileName(), "r" )) != NULL ) && !Overlay ){ - fclose( indexfp ); - return XB_FILE_EXISTS; - } - else if( indexfp ) fclose( indexfp ); - - if(( indexfp = fopen( GetFileName(), "w+b" )) == NULL ){ - return XB_OPEN_ERROR; - } - -#ifdef XB_LOCKING_ON - /* - ** Must turn off buffering when multiple programs may be accessing - ** index files. - */ - setbuf( indexfp, NULL ); -#endif - -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// if((rc = LockIndex( XB_LOCK )) != 0) -// return rc; -#endif - - /* parse the expression */ - IxExp = new xbExpn( dbf->xbase ); - if(( rc = IxExp->BuildExpressionTree( Exp, strlen( Exp ), dbf )) != XB_NO_ERROR ) - return rc; - -// ExpressionTree = dbf->xbase->GetTree(); -// dbf->xbase->SetTreeToNull(); - - /* build the header record */ - memset( &HeadNode, 0x00, sizeof( NtxHeadNode )); - HeadNode.Signature = 0x6; // Clipper 5.x - HeadNode.Version = 1; - HeadNode.StartNode = 1024L; - KeyLen = CalcKeyLen(); - - // TODO - // What is the Clipper key length limit? - if( KeyLen == 0 || KeyLen > 100 ){ /* 100 byte key length limit */ - -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return XB_INVALID_KEY; - } else { - HeadNode.KeyLen = KeyLen; - } - - // This is not the algorithm that Clipper uses. I cant figure out - // what they use from looking at the examples. - // This is correct tho. - HeadNode.KeysPerNode = (xbUShort) - (( XB_NTX_NODE_SIZE - (2 * sizeof( xbUShort ))) / (HeadNode.KeyLen + 10 )) - 1; - if( HeadNode.KeysPerNode % 2 ) - HeadNode.KeysPerNode--; - - HeadNode.HalfKeysPerNode = (xbUShort) HeadNode.KeysPerNode / 2; - HeadNode.KeySize = HeadNode.KeyLen + 8; -// while(( HeadNode.KeySize % 4 ) != 0 ) HeadNode.KeySize++; /* multiple of 4*/ - HeadNode.Unique = Unique; - strncpy( HeadNode.KeyExpression, Exp, 255 ); - - rc=AllocKeyBufs(); - if(rc) { - fclose(indexfp); - return rc; - }; - - if(( rc = PutHeadNode( &HeadNode, indexfp, 0 )) != 0 ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return rc; - } - /* write node #1 all 0x00 */ - for( i = 0; i < XB_NTX_NODE_SIZE; i++ ){ - if(( fwrite( "\x00", 1, 1, indexfp )) != 1 ){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - fclose( indexfp ); - return XB_WRITE_ERROR; - } - } - - if((rc = GetLeafNode(HeadNode.StartNode, 1)) != 0){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return rc; - } - - for( i = 0; i < HeadNode.KeysPerNode + 1; i++ ) - CurNode->offsets[i] = (i * HeadNode.KeySize) + - 2 + (2 * (HeadNode.KeysPerNode + 1)); - - if((rc = PutLeafNode(HeadNode.StartNode, CurNode )) != 0){ -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return rc; - } - -#ifdef XB_LOCKING_ON -// if( dbf->GetAutoLock() ) -// LockIndex( XB_UNLOCK ); -#endif - return dbf->AddIndexToIxList( index, GetFileName()); -} -/***********************************************************************/ -//! Short description. -/*! - \param RecNo - \param n - \param NodeNo -*/ -xbShort xbNtx::PutLeftNodeNo( xbShort RecNo, xbNodeLink *n, xbLong NodeNo ) -{ - /* This routine sets n node's leftnode number */ - NtxLeafNode *temp; - char *p; - xbUShort itemOffset; - if( !n ) return XB_INVALID_NODELINK; - temp = &n->Leaf; - if( RecNo < 0 || RecNo > HeadNode.KeysPerNode) - return XB_INVALID_KEY; - p = temp->KeyRecs; - itemOffset = GetItemOffset(RecNo, n, 1); - p += itemOffset; - dbf->xbase->PutLong( p, NodeNo ); - return XB_NO_ERROR; -} -/***********************************************************************/ -//! Short description. -/*! - \param RecNo - \param n - \param DbfNo -*/ -xbShort xbNtx::PutDbfNo( xbShort RecNo, xbNodeLink *n, xbLong DbfNo ) -{ - /* This routine sets n node's dbf number */ - - NtxLeafNode *temp; - char *p; - xbUShort itemOffset; - if( !n ) return XB_INVALID_NODELINK; - temp = &n->Leaf; - if( RecNo < 0 || RecNo > (HeadNode.KeysPerNode)) - return XB_INVALID_KEY; - itemOffset = GetItemOffset(RecNo, n, 1); - p = temp->KeyRecs; - p += itemOffset; - p += 4; - dbf->xbase->PutLong( p, DbfNo ); - return XB_NO_ERROR; -} -/************************************************************************/ -//! Short description. -/*! - \param l - \param n -*/ -xbShort xbNtx::PutLeafNode( xbLong l, xbNodeLink *n ) -{ - NtxLeafNode *temp; - char *p; - - if(( _fseek( indexfp, (xbOffT)l , SEEK_SET )) != 0 ){ - fclose( indexfp ); - return XB_SEEK_ERROR; - } - - temp = &n->Leaf; - p = temp->KeyRecs; - dbf->xbase->PutShort( p, temp->NoOfKeysThisNode ); - - // The offsets at the head of each leaf are not necessarly in order. - p += 2; - for( int i = 0; i < HeadNode.KeysPerNode + 1; i++){ - dbf->xbase->PutShort( p, n->offsets[i] ); - p += 2; - } - - if(( fwrite( &n->Leaf.KeyRecs, XB_NTX_NODE_SIZE, 1, indexfp )) != 1 ){ - fclose( indexfp ); - return XB_WRITE_ERROR; - } - - PutHeadNode(&HeadNode, indexfp, 1); - return 0; -} -/************************************************************************/ -//! Short description. -/*! - \param Head - \param f - \param UpdateOnly -*/ -xbShort xbNtx::PutHeadNode( NtxHeadNode * Head, FILE * f, xbShort UpdateOnly ) -{ - char buf[4]; - char *p; - - if(( _fseek( f, 0L, SEEK_SET )) != 0 ){ - fclose( f ); - return XB_SEEK_ERROR; - } - - memset( buf, 0x00, 2 ); - dbf->xbase->PutUShort( buf, Head->Signature ); - if(( fwrite( &buf, 2, 1, f )) != 1 ){ - fclose( f ); - return XB_WRITE_ERROR; - } - - memset( buf, 0x00, 2 ); - dbf->xbase->PutUShort( buf, Head->Version ); - if(( fwrite( &buf, 2, 1, f )) != 1 ){ - fclose( f ); - return XB_WRITE_ERROR; - } - - memset( buf, 0x00, 4 ); - dbf->xbase->PutULong( buf, Head->StartNode ); - if(( fwrite( &buf, 4, 1, f )) != 1 ){ - fclose( f ); - return XB_WRITE_ERROR; - } - - memset( buf, 0x00, 4 ); - dbf->xbase->PutULong( buf, Head->UnusedOffset ); - if(( fwrite( &buf, 4, 1, f )) != 1 ){ - fclose( f ); - return XB_WRITE_ERROR; - } - - if( UpdateOnly ){ - fflush(indexfp); - return XB_NO_ERROR; - } - - memset( buf, 0x00, 2 ); - dbf->xbase->PutUShort( buf, Head->KeySize ); - if(( fwrite( &buf, 2, 1, f )) != 1 ){ - fclose( f ); - return XB_WRITE_ERROR; - } - - memset( buf, 0x00, 2 ); - dbf->xbase->PutUShort( buf, Head->KeyLen ); - if(( fwrite( &buf, 2, 1, f )) != 1 ){ - fclose( f ); - return XB_WRITE_ERROR; - } - - memset( buf, 0x00, 2 ); - dbf->xbase->PutUShort( buf, Head->DecimalCount ); - if(( fwrite( &buf, 2, 1, f )) != 1 ){ - fclose( f ); - return XB_WRITE_ERROR; - } - - memset( buf, 0x00, 2 ); - dbf->xbase->PutUShort( buf, Head->KeysPerNode ); - if(( fwrite( &buf, 2, 1, f )) != 1 ){ - fclose( f ); - return XB_WRITE_ERROR; - } - - memset( buf, 0x00, 2 ); - dbf->xbase->PutUShort( buf, Head->HalfKeysPerNode ); - if(( fwrite( &buf, 2, 1, f )) != 1 ){ - fclose( f ); - return XB_WRITE_ERROR; - } - - p = HeadNode.KeyExpression; - while(*p){ - *p = tolower(*p); - p++; - } - - if(( fwrite( &Head->KeyExpression, 256, 1, f )) != 1 ){ - fclose( f ); - return XB_WRITE_ERROR; - } - - memset( buf, 0x00, 1 ); - buf[0] = Head->Unique; - if(( fwrite( &buf, 1, 1, f )) != 1 ){ - fclose( f ); - return XB_WRITE_ERROR; - } - - if(( fwrite( &Head->NotUsed, 745, 1, f )) != 1 ){ - fclose( f ); - return XB_WRITE_ERROR; - } - return 0; -} - -xbShort xbNtx::TouchIndex( void ) -{ - xbShort rc; - if (( rc = GetHeadNode()) != XB_NO_ERROR) return rc; - HeadNode.Version++; - if (( rc = PutHeadNode(&HeadNode, indexfp, 1)) != XB_NO_ERROR) return rc; - return XB_NO_ERROR; -} -/************************************************************************/ -//! Short description. -/*! - \param RecNo - \param n -*/ -xbShort xbNtx::PutKeyData( xbShort RecNo, xbNodeLink *n ) -{ - /* This routine copies the KeyBuf data into xbNodeLink n */ - NtxLeafNode *temp; - char *p; - xbShort i; - xbUShort itemOffset; - if( !n ) return XB_INVALID_NODELINK; - temp = &n->Leaf; - if( RecNo < 0 || RecNo > (HeadNode.KeysPerNode)) - return XB_INVALID_KEY; - itemOffset = GetItemOffset(RecNo, n, 1); - p = temp->KeyRecs; - p += itemOffset; - p += 8; - for( i = 0; i < HeadNode.KeyLen; i++ ){ - *p = KeyBuf[i]; - p++; - } - return XB_NO_ERROR; -} -/************************************************************************/ -//! Short description. -/*! - \param n - \param pos - \param d - \param l - \param w -*/ -xbShort xbNtx::PutKeyInNode( xbNodeLink * n, xbShort pos, xbLong d, xbLong l, xbShort w ) -{ - /* check the node */ - if( !n ) return XB_INVALID_NODELINK; - if( pos < 0 || pos > HeadNode.KeysPerNode ) return XB_INVALID_RECORD; - if( n->Leaf.NoOfKeysThisNode >= HeadNode.KeysPerNode ) return XB_NODE_FULL; - - InsertKeyOffset(pos, n); - PutKeyData( pos, n ); - PutDbfNo( pos, n, d ); - PutLeftNodeNo( pos, n, l ); - n->Leaf.NoOfKeysThisNode++; - if( w ) - return PutLeafNode( n->NodeNo, n ); - else - return 0; -} -/************************************************************************/ -//! Short description. -/*! - \param n1 - \param n2 - \param pos - \param d -*/ -xbShort xbNtx::SplitLeafNode( xbNodeLink *n1, xbNodeLink *n2, xbShort pos, xbLong d ) -{ - xbShort i,j,rc; - xbShort temp; - xbShort start; - xbShort end; -// xbShort length; - - if( !n1 || !n2 ) return XB_INVALID_NODELINK; - if( pos < 0 || pos > HeadNode.KeysPerNode ) return XB_INVALID_RECORD; - -// length = strlen(KeyBuf); - - // If the new key goes in the first node. - if( pos < HeadNode.HalfKeysPerNode ){ - // Setup key to insert into parent - memcpy(PushItem.Key, - GetKeyData(HeadNode.HalfKeysPerNode -1, n1), HeadNode.KeyLen); - PushItem.RecordNumber = GetDbfNo(HeadNode.HalfKeysPerNode -1, n1); - PushItem.Node = 0L; - start = pos; - end = HeadNode.HalfKeysPerNode - 1; - temp = n1->offsets[end]; - for( i = end; i > start; i--) - n1->offsets[i] = n1->offsets[i-1]; - - n1->offsets[start] = temp; - // Insert new key - PutKeyData( start , n1 ); - PutDbfNo ( start , n1, d ); - } else { - // If the passed-in key IS median key, just copy it. - if( pos == HeadNode.HalfKeysPerNode ){ - memcpy(PushItem.Key, KeyBuf, HeadNode.KeyLen); - PushItem.RecordNumber = d; - start = pos; - end = pos; - } else { - // Otherwise, the median key will be middle key because the - // new key will be inserted somewhere above the middle. - memcpy( PushItem.Key, - GetKeyData(HeadNode.HalfKeysPerNode, n1), - HeadNode.KeyLen); - PushItem.RecordNumber = GetDbfNo(HeadNode.HalfKeysPerNode, n1); - start = HeadNode.HalfKeysPerNode ; - end = pos -1; - } - temp = n1->offsets[start]; - for( i = start; i < end; i++) - n1->offsets[i] = n1->offsets[i+1]; - - n1->offsets[end] = temp; - - // Insert new key - PutKeyData( pos -1 , n1 ); - PutDbfNo ( pos -1 , n1, d ); - } - - // Dup the node data - memcpy(n2->Leaf.KeyRecs, n1->Leaf.KeyRecs, XB_NTX_NODE_SIZE); - - // Dup the offsets - for( i = 0; i < HeadNode.KeysPerNode +1; i++) - n2->offsets[i] = n1->offsets[i]; - - // Setup the second node - for(j=0, i=HeadNode.HalfKeysPerNode; i < HeadNode.KeysPerNode; i++, j++ ){ - temp = n2->offsets[j]; - n2->offsets[j] = n2->offsets[i]; - n2->offsets[i] = temp; - } - - // Get the last offset for both nodes - temp = n2->offsets[j]; - n2->offsets[j] = n2->offsets[HeadNode.KeysPerNode]; - n2->offsets[HeadNode.KeysPerNode] = temp; - - // Set the new count of both nodes - n2->Leaf.NoOfKeysThisNode = HeadNode.HalfKeysPerNode; - n1->Leaf.NoOfKeysThisNode = HeadNode.HalfKeysPerNode; - - if(( rc = PutLeafNode( n1->NodeNo, n1 )) != 0 ) - return rc; - if(( rc = PutLeafNode( n2->NodeNo, n2 )) != 0 ) - return rc; - return 0; -} -/************************************************************************/ -//! Short description. -/*! - \param n1 - \param n2 - \param -*/ -xbShort xbNtx::SplitINode( xbNodeLink *n1, xbNodeLink *n2, xbLong ) - /* parent, tempnode, tempnodeno */ -{ - xbShort i,j,rc; - xbShort temp; - xbShort pos = n1->CurKeyNo; - xbShort start; - xbShort end; - xbLong n1LastNodeNo = 0; - - NtxItem oldPushItem; - oldPushItem.Node = PushItem.Node; - oldPushItem.RecordNumber = PushItem.RecordNumber; - memcpy(oldPushItem.Key, PushItem.Key, sizeof(PushItem.Key)); - - // n2->NodeNo = HeadNode.TotalNodes++; - n2->NodeNo = GetNextNodeNo(); - - // If the new key goes in the first node. - if( pos < HeadNode.HalfKeysPerNode ){ - // Setup key to insert into parent - memcpy(PushItem.Key, - GetKeyData(HeadNode.HalfKeysPerNode -1, n1), HeadNode.KeyLen); - PushItem.RecordNumber = GetDbfNo(HeadNode.HalfKeysPerNode -1, n1); - PushItem.Node = n2->NodeNo; - n1LastNodeNo = GetLeftNodeNo(HeadNode.HalfKeysPerNode -1, n1); - start = pos; - end = HeadNode.HalfKeysPerNode - 1; - - // Insert the new key. - temp = n1->offsets[end]; - for( i = end; i > start; i--) - n1->offsets[i] = n1->offsets[i-1]; - n1->offsets[start] = temp; - } else { - // If the passed-in key IS median key, just copy it. - if( pos == HeadNode.HalfKeysPerNode ){ - PutLeftNodeNo(0, n2, oldPushItem.Node); - // PushItem should remain the same, except for its left pointer - PushItem.Node = n2->NodeNo; -// start = pos; unused code -// end = pos; unused code - } else { - // Otherwise, the median key will be middle key becasue the - // new key will be inserted somewhere above the middle. - memcpy( PushItem.Key, - GetKeyData(HeadNode.HalfKeysPerNode, n1), - HeadNode.KeyLen); - PushItem.RecordNumber = GetDbfNo(HeadNode.HalfKeysPerNode, n1); - PushItem.Node = n2->NodeNo; - n1LastNodeNo = GetLeftNodeNo(HeadNode.HalfKeysPerNode, n1); - -// start = HeadNode.HalfKeysPerNode + 1; - start = HeadNode.HalfKeysPerNode; - end = pos -1; - - // Insert the new key. - temp = n1->offsets[start]; - for( i = start; i < end; i++) - n1->offsets[i] = n1->offsets[i+1]; - n1->offsets[end] = temp; - pos--; - } - } - - /* restore original key */ - memcpy( KeyBuf, oldPushItem.Key, HeadNode.KeyLen + 1); - - // Insert new key - PutKeyData( pos, n1 ); - PutDbfNo ( pos, n1, oldPushItem.RecordNumber); - PutLeftNodeNo( pos, n1, GetLeftNodeNo (pos + 1, n1)); - PutLeftNodeNo( pos + 1 /* +1 ?*/, n1, oldPushItem.Node /* t */ ); - - // Dup the node data into the new page - memcpy(n2->Leaf.KeyRecs, n1->Leaf.KeyRecs, XB_NTX_NODE_SIZE); - - // Dup the offsets - for( i = 0; i < HeadNode.KeysPerNode +1; i++){ - n2->offsets[i] = n1->offsets[i]; - } - - // Setup the second node - for( j = 0, i = HeadNode.HalfKeysPerNode; i<HeadNode.KeysPerNode; i++,j++ ){ - temp = n2->offsets[j]; - n2->offsets[j] = n2->offsets[i]; - n2->offsets[i] = temp; - } - - // Get the last offset for both nodes - temp = n2->offsets[j]; - n2->offsets[j] = n2->offsets[HeadNode.KeysPerNode]; - n2->offsets[HeadNode.KeysPerNode] = temp; - PutLeftNodeNo(HeadNode.HalfKeysPerNode, n1, n1LastNodeNo); - - // Set the new count of both nodes - n2->Leaf.NoOfKeysThisNode = HeadNode.HalfKeysPerNode; - n1->Leaf.NoOfKeysThisNode = HeadNode.HalfKeysPerNode; - - if((rc = PutLeafNode( n1->NodeNo,n1 )) != 0) return rc; - if((rc = PutLeafNode( n2->NodeNo,n2 )) != 0) return rc; - return 0; -} -/************************************************************************/ -//! Short description. -/*! - \param RecBufSw - \param KeyBufSw -*/ -xbShort xbNtx::CreateKey( xbShort RecBufSw, xbShort KeyBufSw ) -{ - /* RecBufSw 0 Use RecBuf */ - /* 1 Use RecBuf2 */ - /* KeyBufSw 0 Use KeyBuf */ - /* 1 Use KeyBuf2 */ - - xbShort rc; - xbExpNode * TempNode; - - if(( rc = IxExp->ProcessExpression( RecBufSw )) != XB_NO_ERROR ) - return rc; - TempNode = (xbExpNode *) IxExp->Pop(); - if( !TempNode ) return XB_INVALID_KEY; - - if( KeyBufSw ){ - memset( KeyBuf2, 0x00, HeadNode.KeyLen + 1 ); - memcpy( KeyBuf2, TempNode->StringResult, XB_MIN(HeadNode.KeyLen + 1, TempNode->DataLen) ); - } else { - memset( KeyBuf, 0x00, HeadNode.KeyLen + 1 ); - memcpy( KeyBuf, TempNode->StringResult, XB_MIN(HeadNode.KeyLen + 1, TempNode->DataLen) ); - } -// if( !TempNode->InTree ) dbf->xbase->FreeExpNode( TempNode ); - if( !TempNode->InTree ) delete TempNode; - return 0; -} -/************************************************************************/ -//! Short description. -/*! - \param key -*/ -xbShort -xbNtx::GetCurrentKey(char *key) -{ - CreateKey(0, 0); - memcpy(key, KeyBuf, HeadNode.KeyLen + 1); - return 0; -} -/************************************************************************/ -//! Short description. -/*! - \param DbfRec -*/ -xbShort xbNtx::AddKey( xbLong DbfRec ) -{ - /* This routine assumes KeyBuf contains the contents of the index to key */ - - xbShort i,rc; - xbNodeLink * TempNode; - xbNodeLink * Tparent; - xbLong TempNodeNo; /* new, unattached leaf node no */ - - /* find node key belongs in */ - rc = FindKey( KeyBuf, HeadNode.KeyLen, 0 ); - if( rc == XB_FOUND && HeadNode.Unique ) - return XB_KEY_NOT_UNIQUE; - - /************************************************/ - /* section A - if room in node, add key to node */ - /************************************************/ - - if( CurNode->Leaf.NoOfKeysThisNode < HeadNode.KeysPerNode ){ - if(( rc = PutKeyInNode( CurNode,CurNode->CurKeyNo,DbfRec,0L,1)) != 0) - return rc; - if(( rc = PutHeadNode( &HeadNode, indexfp, 1 )) != 0) - return rc; - return XB_NO_ERROR; - } - - /***********************************************************************/ - /* section B - split leaf node if full and put key in correct position */ - /***********************************************************************/ - - TempNode = GetNodeMemory(); - // Create a new page - TempNode->NodeNo = GetNextNodeNo(); - - rc = SplitLeafNode( CurNode, TempNode, CurNode->CurKeyNo, DbfRec ); - if( rc ) return rc; - - /* TempNode is on disk, now we have to point someone above to - that node. Keep the NodeNo of the on disk new node. - */ - TempNodeNo = TempNode->NodeNo; - ReleaseNodeMemory( TempNode ); - - /* - PushItem also contains the key to put into the parent - PushItem should point at TempNode - */ - PushItem.Node = TempNodeNo; - - /*****************************************************/ - /* section C go up tree splitting nodes as necessary */ - /*****************************************************/ - - Tparent = CurNode->PrevNode; - - while( Tparent && Tparent->Leaf.NoOfKeysThisNode >= HeadNode.KeysPerNode ){ - TempNode = GetNodeMemory(); - if( !TempNode ) - return XB_NO_MEMORY; - - rc = SplitINode( Tparent, TempNode, TempNodeNo ); - if( rc ) return rc; - TempNodeNo = TempNode->NodeNo; - ReleaseNodeMemory( TempNode ); - ReleaseNodeMemory( CurNode ); - CurNode = Tparent; - CurNode->NextNode = NULL; - Tparent = CurNode->PrevNode; - } - - /************************************************************/ - /* Section D if CurNode is split root, create new root */ - /************************************************************/ - - /* at this point - CurNode = The node that was just split - TempNodeNo = The new node split off from CurNode */ - - if(CurNode->NodeNo == HeadNode.StartNode ){ - TempNode = GetNodeMemory(); - if( !TempNode ) - return XB_NO_MEMORY; - - memcpy( KeyBuf, PushItem.Key, HeadNode.KeyLen ); - PutKeyData( 0, TempNode ); - PutDbfNo ( 0, TempNode, PushItem.RecordNumber ); - PutLeftNodeNo( 0, TempNode, CurNode->NodeNo ); - PutLeftNodeNo( 1, TempNode, PushItem.Node ); - TempNode->NodeNo = GetNextNodeNo(); - TempNode->Leaf.NoOfKeysThisNode++; - HeadNode.StartNode = TempNode->NodeNo; - rc = PutLeafNode( TempNode->NodeNo, TempNode ); - if( rc ) return rc; - rc = PutHeadNode( &HeadNode, indexfp, 1 ); - if( rc ) return rc; - ReleaseNodeMemory( TempNode ); - return XB_NO_ERROR; - } - /**********************************/ - /* Section E make room in parent */ - /**********************************/ - InsertKeyOffset(Tparent->CurKeyNo, Tparent); - - /* put key in parent */ - - i = Tparent->CurKeyNo; - memcpy( KeyBuf, PushItem.Key, HeadNode.KeyLen); - PutKeyData( i, Tparent ); - - PutDbfNo( i, Tparent, PushItem.RecordNumber); - PutLeftNodeNo( i , Tparent, CurNode->NodeNo ); - PutLeftNodeNo( i + 1 , Tparent, TempNodeNo ); - Tparent->Leaf.NoOfKeysThisNode++; - - rc = PutLeafNode( Tparent->NodeNo, Tparent ); - if( rc ) return rc; - rc = PutHeadNode( &HeadNode, indexfp, 1 ); - if( rc ) return rc; - - return XB_NO_ERROR; -} -/***********************************************************************/ -//! Short description. -/*! - \param n -*/ -xbShort xbNtx::UpdateParentKey( xbNodeLink * n ) -{ -/* this routine goes backwards thru the node chain looking for a parent - node to update */ - - xbNodeLink * TempNode; - - if( !n ) return XB_INVALID_NODELINK; - if( !GetDbfNo( 0, n )){ - std::cout << "Fatal index error - Not a leaf node" << n->NodeNo << std::endl; -// exit(0); - return XB_NOT_LEAFNODE; - } - TempNode = n->PrevNode; - - while( TempNode ){ - if( TempNode->CurKeyNo < TempNode->Leaf.NoOfKeysThisNode ){ - memcpy(KeyBuf,GetKeyData(n->Leaf.NoOfKeysThisNode-1,n),HeadNode.KeyLen); - PutKeyData( TempNode->CurKeyNo, TempNode ); - return PutLeafNode( TempNode->NodeNo, TempNode ); - } - TempNode = TempNode->PrevNode; - } - return XB_NO_ERROR; -} -/***********************************************************************/ -//! Short description. -/*! - \param n -*/ -/* This routine queues up a list of nodes which have been emptied */ -void xbNtx::UpdateDeleteList( xbNodeLink *n ) -{ - n->NextNode = DeleteChain; - DeleteChain = n; -} -/***********************************************************************/ -//! Short description. -/*! -*/ -/* Delete nodes from the node list - for now we leave the empty nodes */ -/* dangling in the file. Eventually we will remove nodes from the file */ - -void xbNtx::ProcessDeleteList( void ) -{ - if( DeleteChain ){ - ReleaseNodeMemory( DeleteChain ); - DeleteChain = NULL; - } -} -/***********************************************************************/ -//! Short description. -/*! -*/ -xbShort xbNtx::KeyWasChanged( void ) -{ - CreateKey( 0, 0 ); /* use KeyBuf, RecBuf */ - CreateKey( 1, 1 ); /* use KeyBuf2, RecBuf2 */ - if( CompareKey( KeyBuf, KeyBuf2, HeadNode.KeyLen ) != 0 ) - return 1; - else - return 0; -} -/***********************************************************************/ -//! Short description. -/*! - \param DbfRec -*/ -xbShort xbNtx::DeleteKey( xbLong DbfRec ) -{ -/* this routine assumes the key to be deleted is in KeyBuf */ - - xbShort rc; - - // FindKey will set CurNodeNo on evey page down to the - // key being deleted. This is important. Plus we - // need to be able to find the key to delete it. - CurNode = NULL; - if(( rc = FindKey( KeyBuf, DbfRec )) != XB_FOUND ) - return rc; - - // Then delete it - // next sentence modified 8/20/03 - gkunkel - if(( rc = DeleteKeyFromNode( CurNode->CurKeyNo, CurNode )) != XB_NO_ERROR ) - return rc; - - CurDbfRec = GetDbfNo( CurNode->CurKeyNo, CurNode ); - if(( rc = PutHeadNode( &HeadNode, indexfp, 1 )) != 0 ) - return rc; - return XB_NO_ERROR; -} - -//! Short description. -/*! - \param pos - \param n -*/ -xbShort -xbNtx::DeleteKeyFromNode(xbShort pos, xbNodeLink *n ) -{ - xbNodeLink *TempNode; - xbShort rc; - - // Check to see if this is an inode - if( GetLeftNodeNo( 0 , n ) != 0 ){ - // Copy the rightmost key from the left node. - TempNode = n; - GetLeafNode ( GetLeftNodeNo (n->CurKeyNo, n), 1); - while(( rc = GetLeftNodeNo( 0, CurNode )) != 0 ) - GetLeafNode ( GetLeftNodeNo (CurNode->Leaf.NoOfKeysThisNode, CurNode), 1); - - // Get the key Data - strcpy (KeyBuf , GetKeyData( CurNode->Leaf.NoOfKeysThisNode -1, CurNode)); - PutKeyData( pos, TempNode ); - - // Get the xbDbf no - PutDbfNo (pos, TempNode, GetDbfNo( CurNode->Leaf.NoOfKeysThisNode -1, CurNode) ); - - // We don't change the LeftNodeNo. determined later - // Write the changed node - PutLeafNode( TempNode->NodeNo, TempNode ); - - // Now delete the key from the child - TempNode = CurNode; - - if((rc = PutLeafNode( n->NodeNo,n )) != 0) return rc; - - return DeleteKeyFromNode( TempNode->Leaf.NoOfKeysThisNode -1, TempNode); - } else { - return RemoveKeyFromNode(pos, n); - } -} - -//! Short description. -/*! - \param pos - \param n -*/ -xbShort xbNtx::RemoveKeyFromNode( xbShort pos, xbNodeLink *n ) -{ - xbNodeLink *TempNode; - xbNodeLink *sibling; - xbNodeLink *parent; - xbShort rc; - xbLong newHeadNode = 0; - xbBool harvest = false; - - // Here we are a leaf node.. - - if( n->NodeNo == HeadNode.StartNode && n->Leaf.NoOfKeysThisNode == 1) - // we are about to delete the last node from the head node. - newHeadNode = GetLeftNodeNo( 0 , n ); - - // Remove the key from the current node. - DeleteKeyOffset(pos, n); - n->Leaf.NoOfKeysThisNode--; - - // Check to see if the number of keys left is less then - // 1/2 KeysPerNode - if( ! ( n->NodeNo == HeadNode.StartNode ) - && n->Leaf.NoOfKeysThisNode < HeadNode.HalfKeysPerNode){ - // This observed clipper behavior. - // If less then 1/2 keys per node, then merge with right sibling. - // If no right sibling, merge with left sibling. - parent = n->PrevNode; - - // If the parents cur key is the last key, then take the left node - if( parent->CurKeyNo == parent->Leaf.NoOfKeysThisNode ){ - TempNode = CurNode; - GetLeafNode( GetLeftNodeNo(parent->CurKeyNo -1, parent), 2 ); - sibling = CurNode; - CurNode = TempNode; - - rc = JoinSiblings(parent, parent->CurKeyNo -1, sibling, n); - - // Harvest the empty node, if necessary Clipper keeps the old key - // count on the node, to we can't set it to 0 - if( rc == XB_HARVEST_NODE ) - harvest = true; - - if((rc = PutLeafNode( n->NodeNo,n )) != 0) return rc; - if((rc = PutLeafNode( sibling->NodeNo,sibling )) != 0) return rc; - if((rc = PutLeafNode( parent->NodeNo,parent )) != 0) return rc; - - if(harvest){ - HeadNode.UnusedOffset = n->NodeNo; - // Save the empty xbNodeLink - // ReleaseNodeMemory(n); - // We may have to delete a node from the parent - return RemoveKeyFromNode( parent->CurKeyNo, parent); - } - } else { - // Take the right node - TempNode = CurNode; - GetLeafNode( GetLeftNodeNo(parent->CurKeyNo + 1, parent), 2 ); - sibling = CurNode; - CurNode = TempNode; - - rc = JoinSiblings(parent, parent->CurKeyNo, n, sibling); - // Harvest the empty node, if necessary Clipper keeps the old key - // count on the node, to we can't set it to 0 - if( rc == XB_HARVEST_NODE ) - harvest = true; - - if((rc = PutLeafNode( n->NodeNo,n )) != 0) return rc; - if((rc = PutLeafNode( sibling->NodeNo,sibling )) != 0) return rc; - if((rc = PutLeafNode( parent->NodeNo,parent )) != 0) return rc; - - if( harvest ){ - HeadNode.UnusedOffset = sibling->NodeNo; - // Save the empty xbNodeLink - ReleaseNodeMemory( sibling ); - - // Now the parents->CurKeyNo+1 left pointer is empty, and - // we are about to delete the parent. So move the left node no - // from the parents->CurKeyNo+1 to the parent->CurNodeNo - PutLeftNodeNo( parent->CurKeyNo +1 , parent, - GetLeftNodeNo( parent->CurKeyNo, parent )); - // We may have to delete a node from the parent - return RemoveKeyFromNode( parent->CurKeyNo, parent); - } - } - } else { - if( n->NodeNo == HeadNode.StartNode && n->Leaf.NoOfKeysThisNode == 0 ){ - // we are about to delete the last node from the head node. - HeadNode.UnusedOffset = HeadNode.StartNode; - HeadNode.StartNode = newHeadNode; - } - - if((rc = PutLeafNode( n->NodeNo,n )) != 0) return rc; - // If more then 1/2 keys per node -> done. - return XB_NO_ERROR; - } - return XB_NO_ERROR; -} - -//! Short description. -/*! - \param parent - \param parentPos - \param n1 - \param n2 -*/ -xbShort -xbNtx::JoinSiblings(xbNodeLink *parent, xbShort parentPos, xbNodeLink *n1, xbNodeLink* n2) -{ - // ASSUMES: keys in n1 are less then keys in n2 - // - // Here, the contents of n1 need to be merged with n2. If n1 + parent_key - // + n2 can all fit in n1, then leave n2 empty, and remove the key from the - // parent. - // Otherwise evenly distribute the keys from n1 and n2 over both, resetting - // the parent. - - xbShort i, j; - int totalKeys; - int median; - - // if n1 has exactly (it will never have less) 1/2 keys per node - // then put everything into n1. - if((n1->Leaf.NoOfKeysThisNode + n2->Leaf.NoOfKeysThisNode + 1) <= HeadNode.KeysPerNode){ - int n1LastNodeNo = GetLeftNodeNo(n2->Leaf.NoOfKeysThisNode, n2); - // Bring down the parent - strcpy(KeyBuf, GetKeyData( parentPos, parent )); - PutKeyData( n1->Leaf.NoOfKeysThisNode , n1); - PutDbfNo ( n1->Leaf.NoOfKeysThisNode, n1, GetDbfNo( parentPos, parent ) ); - n1->Leaf.NoOfKeysThisNode++; - - // Copy over the rest of the keys - for(i = n1->Leaf.NoOfKeysThisNode, j = 0; j < n2->Leaf.NoOfKeysThisNode; i++, j++){ - strcpy(KeyBuf, GetKeyData( j, n2 )); - PutKeyData( i, n1); - PutLeftNodeNo( i, n1, GetLeftNodeNo( j, n2) ); - PutDbfNo ( i , n1, GetDbfNo( j, n2 ) ); - } - n1->Leaf.NoOfKeysThisNode += j; - PutLeftNodeNo(n1->Leaf.NoOfKeysThisNode, n1, n1LastNodeNo); - - // We need a way to signal that this node will be harvested. - // Clipper keeps the KeyCount on harvested nodes, it does NOT - // set them to 0. - return XB_HARVEST_NODE; - } else { - // Distribute the keys evenly. Of off by one, the extra - // goes to n1. - - // If n1 contains the greater than keys, then at this point we - // know that n1 has more than 1/2MKPN. therefore we copy - // over untill we get to median. All the while removing - // keys from n2. Then - - totalKeys = n1->Leaf.NoOfKeysThisNode + n2->Leaf.NoOfKeysThisNode + 1; - median = (int) totalKeys/2; - - // If n1 has more keys then n2, then we need to copy the last keys - // of n1 to the beginning of n2. - // Leave HalfKeysPerNode+1 keys in n1, then the last key will - // be copied up to the parent. - if( n1->Leaf.NoOfKeysThisNode > HeadNode.HalfKeysPerNode ){ - // Bring down the parent - InsertKeyOffset(0, n2); - strcpy(KeyBuf, GetKeyData( parentPos, parent )); - PutKeyData( 0 , n2); - PutDbfNo ( 0, n2, GetDbfNo( parentPos, parent ) ); - n2->Leaf.NoOfKeysThisNode++; - PutLeftNodeNo(0, n2, GetLeftNodeNo(n1->Leaf.NoOfKeysThisNode, n1)); - for( i = n1->Leaf.NoOfKeysThisNode -1; i > median; i-- ){ - // Put the key in n2 - InsertKeyOffset(0, n2); - strcpy(KeyBuf, GetKeyData( i, n1 )); - PutKeyData( 0, n2); - PutLeftNodeNo( 0, n2, GetLeftNodeNo( i, n1) ); - PutDbfNo ( 0 , n2, GetDbfNo( i, n1 ) ); - - // Remove the key from the current node. - n1->Leaf.NoOfKeysThisNode--; - n2->Leaf.NoOfKeysThisNode++; - } - // Copy up the last key from n1, that will become the new parent key. - strcpy(KeyBuf, GetKeyData( n1->Leaf.NoOfKeysThisNode -1 , n1 )); - PutKeyData( parentPos, parent); - PutDbfNo ( parentPos , parent, GetDbfNo( n1->Leaf.NoOfKeysThisNode -1, n1) ); - n1->Leaf.NoOfKeysThisNode--; - } else { - xbLong n1LastLeftNodeNo; - xbShort medianOffset = n2->Leaf.NoOfKeysThisNode - median -1; - // Bring down the parent - strcpy(KeyBuf, GetKeyData( parentPos, parent )); - PutKeyData( n1->Leaf.NoOfKeysThisNode , n1); - PutDbfNo ( n1->Leaf.NoOfKeysThisNode, n1, GetDbfNo( parentPos, parent ) ); - n1->Leaf.NoOfKeysThisNode++; - -// 8/20/03 gkunkel n1LastLeftNodeNo = GetLeftNodeNo(medianOffset, n2); - PutLeftNodeNo( n1->Leaf.NoOfKeysThisNode, n1, GetLeftNodeNo(medianOffset, n2)); - - // Moving the median to the parent may have to occur - // before moving the other keys to n1. This we would have - // to calcualte the correct offset from the median - // Copy up the first key from n2 (the median), - // that will become the new parent key. - strcpy(KeyBuf, GetKeyData( medianOffset, n2 )); - PutKeyData( parentPos, parent); - PutDbfNo ( parentPos , parent, GetDbfNo(medianOffset, n2 ) ); - n1LastLeftNodeNo = GetLeftNodeNo(medianOffset, n2); - -// Still investigating the -1 thing with clipper, If anyone has clues, -// please let me know - bob@synxis.com -// if ( n1->Leaf.NoOfKeysThisNode >= (median - 1)) -// { -// // Clipper, don't know why -// PutLeftNodeNo(0, n2 , -1 ); -// std::cout << "Clipper hack" << std::endl; -// } - - DeleteKeyOffset(medianOffset, n2); - n2->Leaf.NoOfKeysThisNode--; - -// xbShort clipperMessedUpIndex = n1->Leaf.NoOfKeysThisNode; - for( i = n1->Leaf.NoOfKeysThisNode, j = 0; j < medianOffset; i++, j++ ){ - strcpy(KeyBuf, GetKeyData( 0, n2 )); - PutKeyData( i, n1); - PutLeftNodeNo( i, n1, GetLeftNodeNo( 0, n2) ); - PutDbfNo ( i , n1, GetDbfNo( 0, n2 ) ); - -// if( i == clipperMessedUpIndex){ -// // Clipper, don't know why -// PutLeftNodeNo(0, n2 , -1 ); -// std::cout << "Clipper hack in loop i = " << i << std::endl; -// } - - // Remove the key from the current node. - DeleteKeyOffset(0, n2); - n2->Leaf.NoOfKeysThisNode--; - n1->Leaf.NoOfKeysThisNode++; - } - PutLeftNodeNo(n1->Leaf.NoOfKeysThisNode, n1, n1LastLeftNodeNo); - - } - } - return XB_NO_ERROR; -} -/************************************************************************/ -//! Short description. -/*! - \param option -*/ -#ifdef XBASE_DEBUG -xbShort xbNtx::CheckIndexIntegrity( const xbShort option ) -{ - /* if option = 1, print out some stats */ - - xbShort rc; - xbLong ctr = 1L; - - if ( option ) std::cout << "Checking NTX " << GetFileName() << std::endl; - rc = dbf->GetRecord( ctr ); - while( ctr < dbf->NoOfRecords() ){ - ctr++; - if( option ) std::cout << "Checking Record " << ctr << std::endl; - if( !dbf->RecordDeleted() ){ - CreateKey( 0, 0 ); - rc = FindKey( KeyBuf, dbf->GetCurRecNo()); - if( rc != XB_FOUND ){ - if( option ){ - std::cout << "Record number " << dbf->GetCurRecNo() - << " Not Found" << std::endl; - std::cout << "Key = " << KeyBuf << std::endl; - } - return rc; - } - } - if(( rc = dbf->GetRecord( ctr )) != XB_NO_ERROR ) - return rc; - } - - if( option ) - std::cout << "Exiting with rc = " << rc << std::endl; - return XB_NO_ERROR; -} -#endif -/***********************************************************************/ -//! Short description. -/*! - \param statusFunc -*/ -xbShort xbNtx::ReIndex(void (*statusFunc)(xbLong itemNum, xbLong numItems)) -{ - /* this method assumes the index has been locked in exclusive mode */ - xbLong l; - xbShort rc, i, saveAutoLock; - NtxHeadNode TempHead; - FILE *t, *temp; - xbString TempName; - - memcpy( &TempHead, &HeadNode, sizeof( struct NtxHeadNode )); - TempHead.StartNode = 1024L; - rc = dbf->xbase->DirectoryExistsInName( GetFileName() ); - if( rc ) { - TempName.assign(GetFileName(), 0, rc); - TempName += "TEMPFILE.NTX"; - } else - TempName = "TEMPFILE.NTX"; - - if(( t = fopen( TempName, "w+b" )) == NULL ) - return XB_OPEN_ERROR; - - if(( rc = PutHeadNode( &TempHead, t, 0 )) != 0 ){ - fclose( t ); - remove( TempName ); - return rc; - } - - for( i = 0; i < XB_NTX_NODE_SIZE; i++ ){ - if(( fwrite( "\x00", 1, 1, t )) != 1 ){ - fclose( t ); - remove( TempName ); - return XB_WRITE_ERROR; - } - } - - temp = indexfp; - indexfp = t; - - if(( rc = GetLeafNode(TempHead.StartNode, 1)) != 0 ) - return rc; - - for(i = 0; i < TempHead.KeysPerNode + 1; i++) - CurNode->offsets[i] = (i * HeadNode.KeySize) + - 2 + (2 * (HeadNode.KeysPerNode + 1)); - - HeadNode.StartNode = TempHead.StartNode; - if((rc = PutLeafNode(TempHead.StartNode, CurNode )) != 0) - return rc; - - indexfp = temp; - - if( fclose( indexfp ) != 0 ) - return XB_CLOSE_ERROR; - - if( fclose( t ) != 0 ) - return XB_CLOSE_ERROR; - - if( remove( GetFileName() ) != 0 ) - return XB_CLOSE_ERROR; - - if( rename( TempName, GetFileName()) != 0 ) - return XB_WRITE_ERROR; - - if(( indexfp = fopen( GetFileName(), "r+b" )) == NULL ) - return XB_OPEN_ERROR; - - saveAutoLock = dbf->GetAutoLock(); - dbf->AutoLockOff(); - - for( l = 1; l <= dbf->NoOfRecords(); l++ ){ - if(statusFunc) - statusFunc(l, dbf->NoOfRecords()); - - if(( rc = dbf->GetRecord(l)) != XB_NO_ERROR ) - return rc; - - if(!dbf->GetRealDelete() || !dbf->RecordDeleted()){ - /* Create the key */ - CreateKey( 0, 0 ); - - /* add key to index */ - if(( rc = AddKey( l )) != XB_NO_ERROR ) - return rc; - } - } - if(saveAutoLock) - dbf->AutoLockOn(); - - return XB_NO_ERROR; -} - -//! Short description. -/*! -*/ -xbLong -xbNtx::GetNextNodeNo() -{ - struct stat FileStat; - int rc; - xbULong FileSize; - - if( HeadNode.UnusedOffset != 0){ - FileSize = HeadNode.UnusedOffset; - HeadNode.UnusedOffset = 0; - PutHeadNode(&HeadNode, indexfp, 1); - return FileSize; - } - - rc = fstat(fileno(indexfp), &FileStat); - if( rc != 0 ) - return 0; - - - FileSize = (xbULong)FileStat.st_size; - // File offset is zero based, so the file size will be the - // offset of the next page. - return FileSize; -} - -//! Short description. -/*! - \param buf - \param len -*/ -void xbNtx::GetExpression(char *buf, int len) -{ - memcpy(buf, HeadNode.KeyExpression, len < 256 ? len : 256); -} - -const char* xbNtx::GetExtWithDot(bool lower) -{ - return lower? ".ntx": ".NTX"; -} - -xbUShort xbNtx::GetKeyLen() -{ - return HeadNode.KeyLen; -} - -const char* xbNtx::GetKeyExpression() -{ - return HeadNode.KeyExpression; -} - -void xbNtx::FreeNodesMemory() -{ - ReleaseNodeMemory(NodeChain, true); - NodeChain = 0; -// ReleaseNodeMemory(CloneChain, true); -// CloneChain = 0; - ReleaseNodeMemory(FreeNodeChain, true); - FreeNodeChain = 0; - ReleaseNodeMemory(DeleteChain, true); - DeleteChain = 0; -} - -#endif /* XB_INDEX_NTX */ |