📄 ndx.cpp
字号:
/*************************************************************************** ndx.cpp - description ------------------- begin : Thu Jan 17 2002 copyright : (C) 2002 by email : ***************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************//* $Id: ndx.cpp,v 1.10 2001/03/21 00:28:53 dbryson Exp $ Xbase project source code NDX indexing routines for X-Base Copyright (C) 1997 StarTech, Gary A. Kunkel This library 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.1 of the License, or (at your option) any later version. This library 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 library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Contact: Mail: Technology Associates, Inc. XBase Project 1455 Deming Way #11 Sparks, NV 89434 USA Email: xbase@techass.com See our website at: xdb.sourceforge.net V 1.0 10/10/97 - Initial release of software V 1.3 11/30/97 - Moved GetLong and GetShort to DBF class V 1.5 1/2/98 - Added Dbase IV memo field support V 1.6a 4/1/98 - Added expression support V 1.6b 4/8/98 - Numeric index keys V 1.7.4b 6/2/98 - Big Endian fix in PutLeafNode - JAM - Fix in Reindex - PS - Fix in Findkey( Tkey, DbfRec ) 9/29/98 - Fix in CreateIndex to calculate KeyLen & size Paul Koufalis pkoufalis@cogicom.com - sequence duplicate keys in dbf# order V 1.8 11/30/98 - Version 1.8 upgrade V 1.9 4/12/99 - Added fix to AddKey routine for dup keys - Modified CreateIndex logic - KeySize field */#ifdef __GNUG__ #pragma implementation "ndx.h"#endif#ifdef __WIN32__#include "xbconfigw32.h"#else#include "xbconfig.h"#endif#include "xbase.h"#include <iostream.h>#ifdef XB_INDEX_NDX#ifdef HAVE_IO_H#include <io.h>#endif#include <stdio.h>#include <stdlib.h>#include <string.h>#include "xbexcept.h"/*! \file ndx.cpp*/#define USE_BSEARCH/***********************************************************************///! Short description/*!*/xbShort xbNdx::CloneNodeChain(){ xbNdxNodeLink * TempNodeS; xbNdxNodeLink * TempNodeT; xbNdxNodeLink * TempNodeT2; if( CloneChain ) ReleaseNodeMemory( CloneChain ); CloneChain = NULL; if( !NodeChain ) return XB_NO_ERROR; TempNodeS = NodeChain; TempNodeT2 = NULL; while( TempNodeS ) { if(( TempNodeT = GetNodeMemory()) == NULL ) { xb_memory_error; } memcpy( TempNodeT, TempNodeS, sizeof( struct xbNdxNodeLink )); TempNodeT->NextNode = NULL; TempNodeT->PrevNode = TempNodeT2; if( !CloneChain ) { TempNodeT2 = TempNodeT; CloneChain = TempNodeT; } else { TempNodeT2->NextNode = TempNodeT; TempNodeT2 = TempNodeT2->NextNode; } TempNodeS = TempNodeS->NextNode; } return XB_NO_ERROR;}/***********************************************************************///! Short description/*!*/xbShort xbNdx::UncloneNodeChain(){ if( NodeChain ) ReleaseNodeMemory( NodeChain ); NodeChain = CloneChain; CloneChain = NULL; CurNode = NodeChain; while( CurNode->NextNode ) CurNode = CurNode->NextNode; return XB_NO_ERROR;}/***********************************************************************///! Short description/*!*//* This routine dumps the node chain to stdout */#ifdef XBASE_DEBUGvoid xbNdx::DumpNodeChain(){ xbNdxNodeLink *n; cout << "\n*************************\n"; cout << "xbNodeLinkCtr = " << xbNodeLinkCtr; cout << "\nReused = " << ReusedxbNodeLinks << "\n"; n = NodeChain; while(n) { cout << "xbNodeLink Chain" << n->NodeNo << "\n"; n = n->NextNode; } n = FreeNodeChain; while(n) { cout << "FreexbNodeLink Chain" << n->NodeNo << "\n"; n = n->NextNode; } n = DeleteChain; while(n) { cout << "DeleteLink Chain" << n->NodeNo << "\n"; 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 xbNdx::ReleaseNodeMemory( xbNdxNodeLink * n ){ xbNdxNodeLink * temp; if( !FreeNodeChain ) FreeNodeChain = n; else /* put this list at the end */ { temp = FreeNodeChain; while( temp->NextNode ) temp = temp->NextNode; temp->NextNode = n; } return;}/***********************************************************************///! Short description/*!*//* This routine returns a node from the free chain if available, *//* otherwise it allocates new memory for the requested node */xbNdxNodeLink * xbNdx::GetNodeMemory( void ){ xbNdxNodeLink * temp; if( FreeNodeChain ) { temp = FreeNodeChain; FreeNodeChain = temp->NextNode; ReusedxbNodeLinks++; } else { temp = (xbNdxNodeLink *) malloc( sizeof( xbNdxNodeLink )); xbNodeLinkCtr++; } memset( temp, 0x00, sizeof( xbNdxNodeLink )); return temp;}/***********************************************************************///! Short description/*!*/#ifdef XBASE_DEBUGvoid xbNdx::DumpHdrNode(){ cout << "\nStart node = " << HeadNode.StartNode; cout << "\nTotal nodes = " << HeadNode.TotalNodes; cout << "\nNo of keys = " << HeadNode.NoOfKeys; cout << "\nKey Length = " << HeadNode.KeyLen; cout << "\nKeys Per Node = " << HeadNode.KeysPerNode; cout << "\nKey type = " << HeadNode.KeyType; cout << "\nKey size = " << HeadNode.KeySize; cout << "\nUnknown 2 = " << HeadNode.Unknown2; cout << "\nUnique = " << HeadNode.Unique; cout << "\nKeyExpression = " << HeadNode.KeyExpression;#ifdef XB_VAR_NODESIZE cout << "\nNodeSize = " << NodeSize;#endif // XB_VAR_NODESIZE cout << "\n";#if 0 FILE * log; if(( log = fopen( "xbase.log", "a+t" )) == NULL ) return; fprintf( log, "\n-------------------" ); fprintf( log, "\nStart node =%ld ", HeadNode.StartNode ); fprintf( log, "\nTotal nodes =%ld ", HeadNode.TotalNodes ); fprintf( log, "\nNo of keys =%ld ", HeadNode.NoOfKeys ); fprintf( log, "\nKey Length =%d ", HeadNode.KeyLen ); fprintf( log, "\nKeys Per Node =%d ", HeadNode.KeysPerNode ); fprintf( log, "\nKey type =%d ", HeadNode.KeyType ); fprintf( log, "\nKey size =%ld ", HeadNode.KeySize ); fprintf( log, "\nUnknown 2 =%d ", HeadNode.Unknown2 ); fprintf( log, "\nUnique =%d ", HeadNode.Unique ); fprintf( log, "\nKeyExpression =%s \n", HeadNode.KeyExpression ); fclose( log );#endif}#endif/***********************************************************************///! Short description/*! \param pdbf*/xbNdx::xbNdx(xbDbf *pdbf) : xbIndex(pdbf) {#ifndef XB_VAR_NODESIZE memset( Node, 0x00, XB_NDX_NODE_SIZE );#else memset( Node, 0x00, XB_MAX_NDX_NODE_SIZE );#endif memset( &HeadNode, 0x00, sizeof( xbNdxHeadNode )); NodeChain = NULL; CloneChain = NULL; FreeNodeChain = NULL; DeleteChain = NULL; CurNode = NULL; xbNodeLinkCtr = 0L; ReusedxbNodeLinks = 0L;#ifndef XB_VAR_NODESIZE NodeSize = XB_NDX_NODE_SIZE;#else NodeSize = XB_DEFAULT_NDX_NODE_SIZE;#endif // XB_VAR_NODESIZE}/***********************************************************************///! Short description/*! \param FileName*/xbShort xbNdx::OpenIndex( const char * FileName ){ int NameLen, rc; NameLen = strlen( FileName ) + 1; if(( rc = dbf->NameSuffixMissing( 2, FileName )) > 0 ) if(( rc = dbf->NameSuffixMissing( 4, FileName )) > 0 ) NameLen += 4; IndexName = FileName; if( rc == 1 ) IndexName += ".ndx"; else if ( rc == 2 ) IndexName += ".NDX"; /* open the file */ if(( indexfp = fopen( IndexName, "r+b" )) == NULL ) xb_open_error(IndexName);#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(F_SETLKW, F_RDLCK)) != 0) return rc;#endif IndexStatus = 1; if(( rc = GetHeadNode()) != 0) { #ifdef XB_LOCKING_ON if( dbf->GetAutoLock() ) LockIndex(F_SETLKW, F_UNLCK);#endif fclose( indexfp ); return rc; } /* parse the expression */ if(( rc = dbf->xbase->BuildExpressionTree( HeadNode.KeyExpression, strlen( HeadNode.KeyExpression ), dbf )) != XB_NO_ERROR ) {#ifdef XB_LOCKING_ON if( dbf->GetAutoLock() ) LockIndex(F_SETLKW, F_UNLCK);#endif return rc; } ExpressionTree = dbf->xbase->GetTree(); dbf->xbase->SetTreeToNull(); //dbf->xbase->DumpExpressionTree(ExpressionTree); KeyBuf = (char *) malloc( HeadNode.KeyLen + 1 ); KeyBuf2 = (char *) malloc( HeadNode.KeyLen + 1); memset( KeyBuf, 0x00, HeadNode.KeyLen + 1 ); memset( KeyBuf2, 0x00, HeadNode.KeyLen + 1 ); rc = dbf->AddIndexToIxList( index, IndexName );#ifdef XB_LOCKING_ON if( dbf->GetAutoLock() ) LockIndex(F_SETLKW, F_UNLCK);#endif return rc;}/***********************************************************************///! Short description/*!*/xbShort xbNdx::CloseIndex( void ){ if( KeyBuf ) { free ( KeyBuf ); KeyBuf = NULL; } if( KeyBuf2 ) { free ( KeyBuf2 ); KeyBuf2 = NULL; } dbf->RemoveIndexFromIxList( index ); fclose( indexfp ); IndexStatus = 0; return 0;}/***********************************************************************///! Short description/*!*/xbShort xbNdx::GetHeadNode( void ){ char *p, *q; xbShort i; if( !IndexStatus ) xb_error(XB_NOT_OPEN); if( fseek( indexfp, 0, SEEK_SET )) xb_io_error(XB_SEEK_ERROR, IndexName); if(( fread( Node, XB_NDX_NODE_SIZE, 1, indexfp )) != 1 ) xb_io_error(XB_READ_ERROR, IndexName); /* load the head node structure */ p = Node; HeadNode.StartNode = dbf->xbase->GetLong ( p ); p+=4; HeadNode.TotalNodes = dbf->xbase->GetLong ( p ); p+=4; HeadNode.NoOfKeys = dbf->xbase->GetLong ( p ); p+=4; HeadNode.KeyLen = dbf->xbase->GetShort( p ); p+=2; HeadNode.KeysPerNode = dbf->xbase->GetShort( p ); p+=2; HeadNode.KeyType = dbf->xbase->GetShort( p ); p+=2; HeadNode.KeySize = dbf->xbase->GetLong ( p ); p+=4; HeadNode.Unknown2 = *p++; HeadNode.Unique = *p++; #ifdef XB_VAR_NODESIZE // // Automagically determine the node size. Note the (2 * sizeof(xbLong)) // is taken directly from CreateIndex(). I don't understand it exactly, // but this is the value used to calculate the number of keys per node. // DTB. // NodeSize = (2 * sizeof(xbLong)) + HeadNode.KeySize * HeadNode.KeysPerNode;//printf("NodeSize = %d\n", NodeSize); if(NodeSize % XB_NDX_NODE_MULTIPLE) NodeSize = ((NodeSize + XB_NDX_NODE_MULTIPLE) / XB_NDX_NODE_MULTIPLE) * XB_NDX_NODE_MULTIPLE;//printf("NodeSize = %d\n", NodeSize);#endif q = HeadNode.KeyExpression; for( i = XB_NDX_NODE_BASESIZE; i < XB_NDX_NODE_SIZE && *p; i++ ) *q++ = *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 xbNdx::GetLeafNode( xbLong NodeNo, xbShort SetNodeChain ){ xbNdxNodeLink *n; if( !IndexStatus ) xb_error(XB_NOT_OPEN); if( fseek( indexfp, NodeNo * XB_NDX_NODE_SIZE, SEEK_SET )) xb_io_error(XB_SEEK_ERROR, IndexName); if(( fread( Node, XB_NDX_NODE_SIZE, 1, indexfp )) != 1 ) xb_io_error(XB_READ_ERROR, IndexName); if( !SetNodeChain ) return 0; if(( n = GetNodeMemory()) == NULL ) xb_memory_error; n->NodeNo = NodeNo; n->CurKeyNo = 0L; n->NextNode = NULL; n->Leaf.NoOfKeysThisNode = dbf->xbase->GetLong( Node ); memcpy( n->Leaf.KeyRecs, Node+4, XB_NDX_NODE_SIZE - 4 ); /* put the node in the chain */ if( SetNodeChain == 1 ) { if( NodeChain == NULL ) /* first one ? */ { NodeChain = n; CurNode = n; CurNode->PrevNode = NULL; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -