summaryrefslogtreecommitdiff
path: root/xbase64/xbntx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbase64/xbntx.cpp')
-rwxr-xr-xxbase64/xbntx.cpp2604
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 */