8065 lines
239 KiB
C
8065 lines
239 KiB
C
/*
|
||
* $Id$
|
||
*/
|
||
|
||
/*
|
||
* xHarbour Project source code:
|
||
* DBFCDX RDD (ver.2)
|
||
*
|
||
* Copyright 1999-2002 Bruno Cantero <bruno@issnet.net>
|
||
* Copyright 2000-2003 Horacio Roldan <harbour_ar@yahoo.com.ar> (portions)
|
||
* Copyright 2003 Przemyslaw Czerpak <druzus@priv.onet.pl> - all code except
|
||
* hb_cdxTagDoIndex and related hb_cdxSort* rewritten.
|
||
* www - http://www.xharbour.org
|
||
*
|
||
* 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, 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 General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License
|
||
* along with this software; see the file COPYING. If not, write to
|
||
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
|
||
*
|
||
* As a special exception, the Harbour Project gives permission for
|
||
* additional uses of the text contained in its release of Harbour.
|
||
*
|
||
* The exception is that, if you link the Harbour libraries with other
|
||
* files to produce an executable, this does not by itself cause the
|
||
* resulting executable to be covered by the GNU General Public License.
|
||
* Your use of that executable is in no way restricted on account of
|
||
* linking the Harbour library code into it.
|
||
*
|
||
* This exception does not however invalidate any other reasons why
|
||
* the executable file might be covered by the GNU General Public License.
|
||
*
|
||
* This exception applies only to the code released by the Harbour
|
||
* Project under the name Harbour. If you copy code from other
|
||
* Harbour Project or Free Software Foundation releases into a copy of
|
||
* Harbour, as the General Public License permits, the exception does
|
||
* not apply to the code that you add in this way. To avoid misleading
|
||
* anyone as to the status of such modified files, you must delete
|
||
* this exception notice from them.
|
||
*
|
||
* If you write modifications of your own for Harbour, it is your choice
|
||
* whether to permit this exception to apply to your modifications.
|
||
* If you do not wish that, delete this exception notice.
|
||
*
|
||
*/
|
||
|
||
|
||
#define HB_CDX_DBGCODE
|
||
//#define HB_CDX_DBGCODE_EXT
|
||
|
||
//#define HB_CDX_DSPDBG_INFO
|
||
//#define HB_CDP_SUPPORT_OFF
|
||
//#define HB_CDX_DBGTIME
|
||
//#define HB_CDX_DBGUPDT
|
||
|
||
#include "hbapi.h"
|
||
#include "hbinit.h"
|
||
#include "hbapierr.h"
|
||
#include "hbapilng.h"
|
||
#include "hbvm.h"
|
||
#include "hbset.h"
|
||
#include "hbrddcdx.h"
|
||
|
||
#define __PRG_SOURCE__ __FILE__
|
||
#ifndef __XHARBOUR__
|
||
#define HB_VM_STACK hb_stack
|
||
#endif
|
||
#ifdef HB_PCODE_VER
|
||
#undef HB_PRG_PCODE_VER
|
||
#define HB_PRG_PCODE_VER HB_PCODE_VER
|
||
#endif
|
||
|
||
#ifndef HB_CDP_SUPPORT_OFF
|
||
/* for nation sorting support */
|
||
#include "hbapicdp.h"
|
||
extern PHB_CODEPAGE s_cdpage;
|
||
#define hb_cdpcharcmp( c1, c2, cdpage ) \
|
||
( ( cdpage && cdpage->lSort ) ? \
|
||
hb_cdpchrcmp( c1, c2, cdpage ) : \
|
||
( (BYTE)(c1) - (BYTE)(c2) ) )
|
||
/*
|
||
#define hb_cdpcharcmp( c1, c2, cdpage ) ( (BYTE)(c1) - (BYTE)(c2) )
|
||
*/
|
||
#endif
|
||
|
||
|
||
/*
|
||
* TODO: !!! hb_cdxFindTag doesn't use bag name!
|
||
* TODO: Tag->fRePos = TURE means that rootPage->...->childLeafPage path is
|
||
* bad and has to be reloaded
|
||
* CurKey->rec == 0 means that there is no correct CurKey
|
||
*/
|
||
|
||
/* create a new Tag (make index) */
|
||
static void hb_cdxTagDoIndex( LPCDXTAG pTag );
|
||
|
||
/* Close Tag */
|
||
static void hb_cdxTagClose( LPCDXTAG pTag );
|
||
|
||
/* free Tag pages from cache */
|
||
static void hb_cdxTagPoolFree( LPCDXTAG pTag, int nPagesLeft );
|
||
|
||
/* Store tag header to index files */
|
||
static void hb_cdxTagHeaderStore( LPCDXTAG pTag );
|
||
|
||
/* write all changed pages in tag cache */
|
||
static void hb_cdxTagPoolFlush( LPCDXTAG pTag );
|
||
|
||
/* Discard all pages in cache (TagClose and TagPoolFree for all Tags) */
|
||
static void hb_cdxIndexDiscardBuffers( LPCDXINDEX pIndex );
|
||
|
||
/* write all changed pages in cache (pagePool and Tag Header) */
|
||
static void hb_cdxIndexFlushBuffers( LPCDXINDEX pIndex );
|
||
|
||
/* free cached pages of index file */
|
||
static void hb_cdxIndexPoolFree( LPCDXINDEX pIndex, int nPagesLeft );
|
||
|
||
/* split Root Page */
|
||
static int hb_cdxPageRootSplit( LPCDXPAGE pPage );
|
||
|
||
|
||
|
||
static RDDFUNCS cdxSuper;
|
||
static RDDFUNCS cdxTable =
|
||
{
|
||
|
||
/* Movement and positioning methods */
|
||
|
||
( DBENTRYP_BP ) hb_cdxBof,
|
||
( DBENTRYP_BP ) hb_cdxEof,
|
||
( DBENTRYP_BP ) hb_cdxFound,
|
||
( DBENTRYP_V ) hb_cdxGoBottom,
|
||
( DBENTRYP_UL ) hb_cdxGoTo,
|
||
( DBENTRYP_I ) hb_cdxGoToId,
|
||
( DBENTRYP_V ) hb_cdxGoTop,
|
||
( DBENTRYP_BIB ) hb_cdxSeek,
|
||
( DBENTRYP_L ) hb_cdxSkip,
|
||
( DBENTRYP_L ) hb_cdxSkipFilter,
|
||
( DBENTRYP_L ) hb_cdxSkipRaw,
|
||
|
||
|
||
/* Data management */
|
||
|
||
( DBENTRYP_VF ) hb_cdxAddField,
|
||
( DBENTRYP_B ) hb_cdxAppend,
|
||
( DBENTRYP_I ) hb_cdxCreateFields,
|
||
( DBENTRYP_V ) hb_cdxDeleteRec,
|
||
( DBENTRYP_BP ) hb_cdxDeleted,
|
||
( DBENTRYP_SP ) hb_cdxFieldCount,
|
||
( DBENTRYP_VF ) hb_cdxFieldDisplay,
|
||
( DBENTRYP_SSI ) hb_cdxFieldInfo,
|
||
( DBENTRYP_SVP ) hb_cdxFieldName,
|
||
( DBENTRYP_V ) hb_cdxFlush,
|
||
( DBENTRYP_PP ) hb_cdxGetRec,
|
||
( DBENTRYP_SI ) hb_cdxGetValue,
|
||
( DBENTRYP_SVL ) hb_cdxGetVarLen,
|
||
( DBENTRYP_V ) hb_cdxGoCold,
|
||
( DBENTRYP_V ) hb_cdxGoHot,
|
||
( DBENTRYP_P ) hb_cdxPutRec,
|
||
( DBENTRYP_SI ) hb_cdxPutValue,
|
||
( DBENTRYP_V ) hb_cdxRecall,
|
||
( DBENTRYP_ULP ) hb_cdxRecCount,
|
||
( DBENTRYP_ISI ) hb_cdxRecInfo,
|
||
( DBENTRYP_I ) hb_cdxRecNo,
|
||
( DBENTRYP_S ) hb_cdxSetFieldExtent,
|
||
|
||
|
||
/* WorkArea/Database management */
|
||
|
||
( DBENTRYP_P ) hb_cdxAlias,
|
||
( DBENTRYP_V ) hb_cdxClose,
|
||
( DBENTRYP_VP ) hb_cdxCreate,
|
||
( DBENTRYP_SI ) hb_cdxInfo,
|
||
( DBENTRYP_V ) hb_cdxNewArea,
|
||
( DBENTRYP_VP ) hb_cdxOpen,
|
||
( DBENTRYP_V ) hb_cdxRelease,
|
||
( DBENTRYP_SP ) hb_cdxStructSize,
|
||
( DBENTRYP_P ) hb_cdxSysName,
|
||
( DBENTRYP_VEI ) hb_cdxEval,
|
||
( DBENTRYP_V ) hb_cdxPack,
|
||
( DBENTRYP_LSP ) hb_cdxPackRec,
|
||
( DBENTRYP_VS ) hb_cdxSort,
|
||
( DBENTRYP_VT ) hb_cdxTrans,
|
||
( DBENTRYP_VT ) hb_cdxTransRec,
|
||
( DBENTRYP_V ) hb_cdxZap,
|
||
|
||
|
||
/* Relational Methods */
|
||
|
||
( DBENTRYP_VR ) hb_cdxChildEnd,
|
||
( DBENTRYP_VR ) hb_cdxChildStart,
|
||
( DBENTRYP_VR ) hb_cdxChildSync,
|
||
( DBENTRYP_V ) hb_cdxSyncChildren,
|
||
( DBENTRYP_V ) hb_cdxClearRel,
|
||
( DBENTRYP_V ) hb_cdxForceRel,
|
||
( DBENTRYP_SVP ) hb_cdxRelArea,
|
||
( DBENTRYP_VR ) hb_cdxRelEval,
|
||
( DBENTRYP_SVP ) hb_cdxRelText,
|
||
( DBENTRYP_VR ) hb_cdxSetRel,
|
||
|
||
|
||
/* Order Management */
|
||
|
||
( DBENTRYP_OI ) hb_cdxOrderListAdd,
|
||
( DBENTRYP_V ) hb_cdxOrderListClear,
|
||
( DBENTRYP_VP ) hb_cdxOrderListDelete,
|
||
( DBENTRYP_OI ) hb_cdxOrderListFocus,
|
||
( DBENTRYP_V ) hb_cdxOrderListRebuild,
|
||
( DBENTRYP_VOI ) hb_cdxOrderCondition,
|
||
( DBENTRYP_VOC ) hb_cdxOrderCreate,
|
||
( DBENTRYP_OI ) hb_cdxOrderDestroy,
|
||
( DBENTRYP_OII ) hb_cdxOrderInfo,
|
||
|
||
|
||
/* Filters and Scope Settings */
|
||
|
||
( DBENTRYP_V ) hb_cdxClearFilter,
|
||
( DBENTRYP_V ) hb_cdxClearLocate,
|
||
( DBENTRYP_V ) hb_cdxClearScope,
|
||
( DBENTRYP_VPLP ) hb_cdxCountScope,
|
||
( DBENTRYP_I ) hb_cdxFilterText,
|
||
( DBENTRYP_SI ) hb_cdxScopeInfo,
|
||
( DBENTRYP_VFI ) hb_cdxSetFilter,
|
||
( DBENTRYP_VLO ) hb_cdxSetLocate,
|
||
( DBENTRYP_VOS ) hb_cdxSetScope,
|
||
( DBENTRYP_VPL ) hb_cdxSkipScope,
|
||
|
||
|
||
/* Miscellaneous */
|
||
|
||
( DBENTRYP_P ) hb_cdxCompile,
|
||
( DBENTRYP_I ) hb_cdxError,
|
||
( DBENTRYP_I ) hb_cdxEvalBlock,
|
||
|
||
|
||
/* Network operations */
|
||
|
||
( DBENTRYP_VSP ) hb_cdxRawLock,
|
||
( DBENTRYP_VL ) hb_cdxLock,
|
||
( DBENTRYP_UL ) hb_cdxUnLock,
|
||
|
||
|
||
/* Memofile functions */
|
||
|
||
( DBENTRYP_V ) hb_cdxCloseMemFile,
|
||
( DBENTRYP_VP ) hb_cdxCreateMemFile,
|
||
( DBENTRYP_SVPB ) hb_cdxGetValueFile,
|
||
( DBENTRYP_VP ) hb_cdxOpenMemFile,
|
||
( DBENTRYP_SVP ) hb_cdxPutValueFile,
|
||
|
||
|
||
/* Database file header handling */
|
||
|
||
( DBENTRYP_V ) hb_cdxReadDBHeader,
|
||
( DBENTRYP_V ) hb_cdxWriteDBHeader,
|
||
|
||
|
||
/* non WorkArea functions */
|
||
( DBENTRYP_I0 ) hb_cdxExit,
|
||
( DBENTRYP_I1 ) hb_cdxDrop,
|
||
( DBENTRYP_I2 ) hb_cdxExists,
|
||
|
||
|
||
/* Special and reserved methods */
|
||
|
||
( DBENTRYP_SVP ) hb_cdxWhoCares
|
||
};
|
||
|
||
|
||
HB_FUNC( _DBFCDX ) {;}
|
||
|
||
HB_FUNC( DBFCDX_GETFUNCTABLE )
|
||
{
|
||
RDDFUNCS * pTable;
|
||
USHORT * uiCount;
|
||
|
||
uiCount = ( USHORT * ) hb_itemGetPtr( hb_param( 1, HB_IT_POINTER ) );
|
||
pTable = ( RDDFUNCS * ) hb_itemGetPtr( hb_param( 2, HB_IT_POINTER ) );
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("DBFCDX_GETFUNCTABLE(%i, %p)", uiCount, pTable));
|
||
|
||
if ( pTable )
|
||
{
|
||
SHORT iRet;
|
||
|
||
if ( uiCount )
|
||
* uiCount = RDDFUNCSCOUNT;
|
||
iRet = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBFFPT" );
|
||
if ( iRet == FAILURE )
|
||
iRet = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBFDBT" );
|
||
if ( iRet == FAILURE )
|
||
iRet = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBF" );
|
||
hb_retni( iRet );
|
||
}
|
||
else
|
||
hb_retni( FAILURE );
|
||
}
|
||
|
||
|
||
HB_INIT_SYMBOLS_BEGIN( dbfcdx1__InitSymbols )
|
||
{ "_DBFCDX", HB_FS_PUBLIC, HB_FUNCNAME( _DBFCDX ), NULL },
|
||
{ "DBFCDX_GETFUNCTABLE", HB_FS_PUBLIC, HB_FUNCNAME( DBFCDX_GETFUNCTABLE ), NULL }
|
||
HB_INIT_SYMBOLS_END( dbfcdx1__InitSymbols )
|
||
|
||
#if defined(_MSC_VER)
|
||
#if _MSC_VER >= 1010
|
||
#pragma data_seg( ".CRT$XIY" )
|
||
#pragma comment( linker, "/Merge:.CRT=.data" )
|
||
#else
|
||
#pragma data_seg( "XIY" )
|
||
#endif
|
||
static HB_$INITSYM hb_vm_auto_dbfcdx1__InitSymbols = dbfcdx1__InitSymbols;
|
||
#pragma data_seg()
|
||
#elif ! defined(__GNUC__)
|
||
#pragma startup dbfcdx1__InitSymbols
|
||
#endif
|
||
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
static void hb_cdxDspTags( LPCDXINDEX pIndex )
|
||
{
|
||
LPCDXTAG pTag = NULL;
|
||
|
||
printf( "\r\n*TAGS*" );
|
||
while ( pIndex )
|
||
{
|
||
printf( "\r\nBAG: [%s] ->", pIndex->szFileName );
|
||
pTag = pIndex->TagList;
|
||
while ( pTag )
|
||
{
|
||
printf( " {%s}", pTag->szName );
|
||
pTag = pTag->pNext;
|
||
}
|
||
pIndex = pIndex->pNext;
|
||
}
|
||
printf( "\r\n*END*\r\n" ); fflush( stdout );
|
||
}
|
||
#endif
|
||
|
||
#ifdef HB_CDX_DBGTIME
|
||
#include <sys/time.h>
|
||
typedef LONGLONG CDXDBGTIME;
|
||
|
||
static CDXDBGTIME cdxTimeIntBld = 0;
|
||
static CDXDBGTIME cdxTimeExtBld = 0;
|
||
static CDXDBGTIME cdxTimeIntBlc = 0;
|
||
static CDXDBGTIME cdxTimeExtBlc = 0;
|
||
static CDXDBGTIME cdxTimeGetKey = 0;
|
||
static CDXDBGTIME cdxTimeFreeKey = 0;
|
||
|
||
static CDXDBGTIME hb_cdxGetTime()
|
||
{
|
||
struct timeval tv;
|
||
gettimeofday(&tv, NULL);
|
||
return ( (CDXDBGTIME) tv.tv_sec * 1000000 + (CDXDBGTIME) tv.tv_usec );
|
||
}
|
||
#endif
|
||
#ifdef HB_CDX_DBGUPDT
|
||
static ULONG cdxWriteNO = 0;
|
||
static ULONG cdxReadNO = 0;
|
||
static SHORT cdxStackSize = 0;
|
||
static SHORT cdxTmpStackSize = 0;
|
||
#endif
|
||
|
||
/*
|
||
* internal DBFCDX function
|
||
*/
|
||
static void hb_cdxErrInternal( char * szMsg )
|
||
{
|
||
hb_errInternal( 9201, szMsg ? szMsg : "hb_cdxErrInternal: data integrity error.", "", "" );
|
||
}
|
||
|
||
static ERRCODE hb_cdxErrorRT( CDXAREAP pArea, USHORT uiGenCode, USHORT uiSubCode, char * filename, USHORT uiFlags )
|
||
{
|
||
PHB_ITEM pError;
|
||
ERRCODE iRet;
|
||
|
||
pError = hb_errNew();
|
||
hb_errPutGenCode( pError, uiGenCode );
|
||
hb_errPutSubCode( pError, uiSubCode );
|
||
hb_errPutDescription( pError, hb_langDGetErrorDesc( uiGenCode ) );
|
||
if ( filename )
|
||
hb_errPutFileName( pError, filename );
|
||
if ( uiFlags )
|
||
hb_errPutFlags( pError, uiFlags );
|
||
iRet = SELF_ERROR( ( AREAP ) pArea, pError );
|
||
hb_itemRelease( pError );
|
||
return iRet;
|
||
}
|
||
|
||
/*
|
||
* create index sort table
|
||
*/
|
||
static void hb_cdxMakeSortTab( CDXAREAP pArea )
|
||
{
|
||
#ifndef HB_CDP_SUPPORT_OFF
|
||
if ( pArea->cdPage && pArea->cdPage->lSort && !pArea->bCdxSortTab )
|
||
{
|
||
int i, j, l;
|
||
BYTE * pbSort;
|
||
BYTE b;
|
||
|
||
pArea->bCdxSortTab = ( BYTE * ) hb_xgrab( 256 );
|
||
pbSort = ( BYTE * ) hb_xgrab( 256 );
|
||
/* this table should be allready quite good sorted so this simple
|
||
algorithms will be one of the most efficient one. */
|
||
for ( i = 0; i <= 255; i++ )
|
||
pbSort[i] = ( BYTE ) i;
|
||
l = 255;
|
||
do
|
||
{
|
||
j = l;
|
||
for( i = 0; i < j; i++ )
|
||
{
|
||
if ( hb_cdpchrcmp( pbSort[i], pbSort[i+1], pArea->cdPage ) > 0 )
|
||
{
|
||
b = pbSort[i+1];
|
||
pbSort[i+1] = pbSort[i];
|
||
pbSort[i] = b;
|
||
l = i;
|
||
}
|
||
}
|
||
} while ( j != l );
|
||
for ( i = 0; i <= 255; i++ )
|
||
pArea->bCdxSortTab[pbSort[i]] = i;
|
||
hb_xfree( pbSort );
|
||
}
|
||
#endif
|
||
}
|
||
|
||
/*
|
||
* create new index key
|
||
*/
|
||
static LPCDXKEY hb_cdxKeyNew( void )
|
||
{
|
||
LPCDXKEY pKey;
|
||
|
||
pKey = ( LPCDXKEY ) hb_xgrab( sizeof( CDXKEY ) );
|
||
memset( pKey, 0, sizeof( CDXKEY ) );
|
||
return pKey;
|
||
}
|
||
|
||
/*
|
||
* Free index key
|
||
*/
|
||
static void hb_cdxKeyFree( LPCDXKEY pKey )
|
||
{
|
||
if ( pKey->val )
|
||
hb_xfree( pKey->val );
|
||
hb_xfree( pKey );
|
||
}
|
||
|
||
/*
|
||
* copy index key, if dst is null create new dst key else destroy dst
|
||
*/
|
||
static LPCDXKEY hb_cdxKeyCopy( LPCDXKEY pKeyDest, LPCDXKEY pKey )
|
||
{
|
||
if ( !pKeyDest )
|
||
pKeyDest = hb_cdxKeyNew();
|
||
else
|
||
{
|
||
pKeyDest->rec = 0;
|
||
if ( pKeyDest->val && pKeyDest->len != pKey->len )
|
||
{
|
||
hb_xfree( pKeyDest->val );
|
||
pKeyDest->val = NULL;
|
||
pKeyDest->len = 0;
|
||
}
|
||
}
|
||
if ( pKey )
|
||
{
|
||
if ( pKey->len )
|
||
{
|
||
if ( !pKeyDest->val )
|
||
pKeyDest->val = (BYTE *) hb_xgrab( pKey->len + 1 );
|
||
memcpy( pKeyDest->val, pKey->val, pKey->len );
|
||
pKeyDest->len = pKey->len;
|
||
pKeyDest->val[ pKeyDest->len ] = '\0';
|
||
}
|
||
pKeyDest->rec = pKey->rec;
|
||
}
|
||
return pKeyDest;
|
||
}
|
||
|
||
/*
|
||
* store bytes value in inkdex key
|
||
*/
|
||
static LPCDXKEY hb_cdxKeyPut( LPCDXKEY pKey, BYTE * pbVal, USHORT uiLen, ULONG ulRec )
|
||
{
|
||
if ( !pKey )
|
||
pKey = hb_cdxKeyNew();
|
||
else
|
||
{
|
||
if ( pKey->val && pKey->len != uiLen )
|
||
{
|
||
hb_xfree( pKey->val );
|
||
pKey->val = NULL;
|
||
pKey->len = 0;
|
||
}
|
||
}
|
||
if ( pbVal && uiLen )
|
||
{
|
||
pKey->len = (BYTE) uiLen;
|
||
if ( !pKey->val )
|
||
pKey->val = ( BYTE * ) hb_xgrab( uiLen + 1 );
|
||
memcpy( pKey->val, pbVal, uiLen );
|
||
pKey->val[ uiLen ] = '\0';
|
||
}
|
||
pKey->rec = ulRec;
|
||
return pKey;
|
||
}
|
||
|
||
/*
|
||
* store string0 value in index key
|
||
*/
|
||
static LPCDXKEY hb_cdxKeyPutC( LPCDXKEY pKey, char * szText, USHORT uiRealLen, ULONG ulRec )
|
||
{
|
||
USHORT uiLen;
|
||
|
||
if ( !pKey )
|
||
pKey = hb_cdxKeyNew();
|
||
else
|
||
{
|
||
if ( pKey->val )
|
||
{
|
||
hb_xfree( pKey->val );
|
||
pKey->val = NULL;
|
||
pKey->len = 0;
|
||
}
|
||
}
|
||
uiLen = (USHORT) ( szText ? strlen( szText ) : 0 );
|
||
if ( uiLen > uiRealLen )
|
||
uiLen = uiRealLen;
|
||
pKey->len = ( BYTE ) uiRealLen;
|
||
pKey->val = ( BYTE * ) hb_xgrab( uiRealLen + 1 );
|
||
if ( uiLen )
|
||
memcpy( pKey->val, szText, uiLen );
|
||
if ( uiLen < uiRealLen )
|
||
memset( &pKey->val[ uiLen ], ' ', uiRealLen - uiLen );
|
||
pKey->val[ uiRealLen ] = '\0';
|
||
pKey->rec = ulRec;
|
||
return pKey;
|
||
}
|
||
|
||
/*
|
||
* compare two values using Tag conditions (len & type)
|
||
*/
|
||
static int hb_cdxValCompare( LPCDXTAG pTag, BYTE * val1, BYTE len1,
|
||
BYTE * val2, BYTE len2, BOOL fExact )
|
||
{
|
||
int iLimit, iResult = 0;
|
||
|
||
iLimit = (len1 > len2) ? len2 : len1;
|
||
|
||
if ( pTag->uiType == 'C' )
|
||
{
|
||
#ifndef HB_CDP_SUPPORT_OFF
|
||
if ( pTag->pIndex->pArea->bCdxSortTab )
|
||
{
|
||
BYTE * pSort = pTag->pIndex->pArea->bCdxSortTab;
|
||
int iPos = 0;
|
||
while ( iResult == 0 && iPos < iLimit )
|
||
{
|
||
iResult = pSort[ val1[ iPos ] ] - pSort[ val2[ iPos ] ];
|
||
iPos++;
|
||
}
|
||
}
|
||
else
|
||
#endif
|
||
if ( iLimit > 0 )
|
||
iResult = memcmp( val1, val2, iLimit );
|
||
|
||
if ( iResult == 0 )
|
||
{
|
||
if ( len1 > len2 )
|
||
iResult = 1;
|
||
else if ( len1 < len2 && fExact )
|
||
iResult = -1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ( iLimit == 0 || (iResult = memcmp( val1, val2, iLimit )) == 0 )
|
||
{
|
||
if ( len1 > len2 )
|
||
iResult = 1;
|
||
else if ( len1 < len2 )
|
||
iResult = -1;
|
||
}
|
||
}
|
||
return iResult;
|
||
}
|
||
|
||
/*
|
||
* store Item in index key
|
||
* TODO: uiType check
|
||
*/
|
||
static LPCDXKEY hb_cdxKeyPutItem( LPCDXKEY pKey, PHB_ITEM pItem, ULONG ulRec, LPCDXTAG pTag, BOOL fTrans, BOOL fSize )
|
||
{
|
||
BYTE buf[CDX_MAXKEY], *ptr;
|
||
BYTE len = 0;
|
||
double d;
|
||
|
||
ptr = &buf[0];
|
||
|
||
switch ( hb_itemType( pItem ) )
|
||
{
|
||
case HB_IT_STRING:
|
||
case HB_IT_STRING | HB_IT_MEMO:
|
||
len = ( BYTE ) HB_MIN( pItem->item.asString.length, pTag->uiLen );
|
||
if ( fSize && len < pTag->uiLen )
|
||
{
|
||
memcpy( ptr, pItem->item.asString.value, len );
|
||
memset( ptr + len, pTag->uiType == 'C' ? ' ' : '\0', pTag->uiLen - len );
|
||
len = pTag->uiLen;
|
||
}
|
||
else
|
||
{
|
||
ptr = ( BYTE * ) pItem->item.asString.value;
|
||
}
|
||
break;
|
||
case HB_IT_INTEGER:
|
||
case HB_IT_LONG:
|
||
case HB_IT_DOUBLE:
|
||
#ifndef HB_LONG_LONG_OFF
|
||
case HB_IT_LONGLONG:
|
||
#endif
|
||
d = hb_itemGetND( pItem );
|
||
HB_DBL2ORD( &d, ptr );
|
||
len = 8;
|
||
break;
|
||
case HB_IT_DATE:
|
||
d = (double) pItem->item.asDate.value;
|
||
HB_DBL2ORD( &d, ptr );
|
||
len = 8;
|
||
break;
|
||
case HB_IT_LOGICAL:
|
||
*ptr = (BYTE) ( hb_itemGetL( pItem ) ? 'T' : 'F' );
|
||
len = 1;
|
||
break;
|
||
default:
|
||
ptr = NULL;
|
||
#ifdef HB_CDX_DBGCODE
|
||
/* TODO: RTerror */
|
||
printf( "hb_cdxKeyPutItem( invalid item type: %i )", hb_itemType( pItem ) );
|
||
#endif
|
||
break;
|
||
}
|
||
pKey = hb_cdxKeyPut( pKey, ptr, len, ulRec );
|
||
#ifndef HB_CDP_SUPPORT_OFF
|
||
if ( fTrans && pTag->uiType == 'C' )
|
||
hb_cdpnTranslate( ( char * ) pKey->val, s_cdpage, pTag->pIndex->pArea->cdPage, pKey->len );
|
||
#endif
|
||
return pKey;
|
||
}
|
||
|
||
/*
|
||
* get Item from index key (TODO: add pTag param)
|
||
*/
|
||
static PHB_ITEM hb_cdxKeyGetItem( LPCDXKEY pKey, PHB_ITEM pItem, USHORT uiType )
|
||
{
|
||
double d;
|
||
|
||
if ( pKey )
|
||
{
|
||
switch( uiType )
|
||
{
|
||
case 'C':
|
||
pItem = hb_itemPutCL( pItem, ( char * ) pKey->val, pKey->len );
|
||
break;
|
||
case 'N':
|
||
HB_ORD2DBL( pKey->val, &d );
|
||
pItem = hb_itemPutND( pItem, d );
|
||
break;
|
||
case 'D':
|
||
HB_ORD2DBL( pKey->val, &d );
|
||
pItem = hb_itemPutDL( pItem, ( LONG ) d );
|
||
break;
|
||
case 'L':
|
||
pItem = hb_itemPutL( pItem, pKey->val[0] == 'T' );
|
||
break;
|
||
default:
|
||
pItem = hb_itemNew( pItem );
|
||
#ifdef HB_CDX_DBGCODE
|
||
printf( "hb_cdxKeyGetItem() ??? (%x)\n", uiType );
|
||
#endif
|
||
}
|
||
}
|
||
else
|
||
pItem = hb_itemNew( pItem );
|
||
|
||
return pItem;
|
||
}
|
||
|
||
/*
|
||
* evaluate key expression and create new Key from the result
|
||
*/
|
||
static LPCDXKEY hb_cdxKeyEval( LPCDXKEY pKey, LPCDXTAG pTag, BOOL fSetWA )
|
||
{
|
||
HB_MACRO_PTR pMacro;
|
||
int iCurrArea = 0;
|
||
CDXAREAP pArea = pTag->pIndex->pArea;
|
||
#ifndef HB_CDP_SUPPORT_OFF
|
||
/* TODO: this hack is not thread safe, s_cdpage has to be thread specific */
|
||
PHB_CODEPAGE cdpTmp = s_cdpage;
|
||
s_cdpage = pArea->cdPage;
|
||
#endif
|
||
|
||
if ( fSetWA && !pTag->nField )
|
||
{
|
||
iCurrArea = hb_rddGetCurrentWorkAreaNumber();
|
||
if ( iCurrArea != pArea->uiArea )
|
||
hb_rddSelectWorkAreaNumber( pArea->uiArea );
|
||
else
|
||
iCurrArea = 0;
|
||
}
|
||
|
||
if ( pTag->nField )
|
||
{
|
||
PHB_ITEM pItem = hb_itemNew( NULL );
|
||
SELF_GETVALUE( ( AREAP ) pArea, pTag->nField, pItem );
|
||
pKey = hb_cdxKeyPutItem( pKey, pItem, pArea->ulRecNo, pTag, FALSE, TRUE );
|
||
hb_itemRelease( pItem );
|
||
}
|
||
else if ( hb_itemType( pTag->pKeyItem ) == HB_IT_BLOCK )
|
||
{
|
||
hb_vmPushSymbol( &hb_symEval );
|
||
hb_vmPush( pTag->pKeyItem );
|
||
hb_vmSend( 0 );
|
||
pKey = hb_cdxKeyPutItem( pKey, &(HB_VM_STACK.Return), pArea->ulRecNo, pTag, FALSE, TRUE );
|
||
}
|
||
else
|
||
{
|
||
pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pKeyItem );
|
||
hb_macroRun( pMacro );
|
||
pKey = hb_cdxKeyPutItem( pKey, hb_stackItemFromTop( -1 ), pArea->ulRecNo, pTag, FALSE, TRUE );
|
||
hb_stackPop();
|
||
}
|
||
|
||
if ( iCurrArea )
|
||
hb_rddSelectWorkAreaNumber( iCurrArea );
|
||
|
||
#ifndef HB_CDP_SUPPORT_OFF
|
||
s_cdpage = cdpTmp;
|
||
#endif
|
||
|
||
return pKey;
|
||
}
|
||
|
||
/*
|
||
* evaluate macro expression
|
||
* the result is on the stack hb_stackItemFromTop(-1)
|
||
* TODO: eliminate it by implementing macro evaluation
|
||
* in SELF_EVALBLOCK( AREAP pArea, PHB_ITEM pExpr)
|
||
*/
|
||
static void hb_cdxMacroRun( CDXAREAP pArea, HB_MACRO_PTR pMacro )
|
||
{
|
||
int iCurrArea;
|
||
iCurrArea = hb_rddGetCurrentWorkAreaNumber();
|
||
if ( iCurrArea != pArea->uiArea )
|
||
hb_rddSelectWorkAreaNumber( pArea->uiArea );
|
||
else
|
||
iCurrArea = 0;
|
||
hb_macroRun( pMacro );
|
||
if ( iCurrArea )
|
||
hb_rddSelectWorkAreaNumber( iCurrArea );
|
||
}
|
||
|
||
/*
|
||
* evaluate conditional expression and return the result
|
||
*/
|
||
static BOOL hb_cdxEvalCond( CDXAREAP pArea, PHB_ITEM pCondItem, BOOL fSetWA )
|
||
{
|
||
HB_MACRO_PTR pMacro;
|
||
int iCurrArea = 0;
|
||
BOOL fRet;
|
||
|
||
if ( fSetWA ) {
|
||
iCurrArea = hb_rddGetCurrentWorkAreaNumber();
|
||
if ( iCurrArea != pArea->uiArea )
|
||
hb_rddSelectWorkAreaNumber( pArea->uiArea );
|
||
else
|
||
iCurrArea = 0;
|
||
}
|
||
|
||
if ( hb_itemType( pCondItem ) == HB_IT_BLOCK )
|
||
{
|
||
hb_vmPushSymbol( &hb_symEval );
|
||
hb_vmPush( pCondItem );
|
||
hb_vmSend( 0 );
|
||
fRet = hb_itemGetL( &(HB_VM_STACK.Return) );
|
||
}
|
||
else
|
||
{
|
||
pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pCondItem );
|
||
hb_macroRun( pMacro );
|
||
fRet = hb_itemGetL( hb_stackItemFromTop( -1 ) );
|
||
hb_stackPop();
|
||
}
|
||
|
||
if ( iCurrArea )
|
||
hb_rddSelectWorkAreaNumber( iCurrArea );
|
||
|
||
return fRet;
|
||
}
|
||
|
||
/*
|
||
* evaluate seek/skip block: {|key, rec| ... }
|
||
*/
|
||
static BOOL hb_cdxEvalSeekCond( LPCDXTAG pTag, PHB_ITEM pCondItem )
|
||
{
|
||
BOOL fRet;
|
||
HB_ITEM ItemKey;
|
||
|
||
if ( hb_itemType( pCondItem ) != HB_IT_BLOCK )
|
||
return TRUE;
|
||
|
||
ItemKey.type = HB_IT_NIL;
|
||
hb_cdxKeyGetItem( pTag->CurKey, &ItemKey, pTag->uiType );
|
||
|
||
hb_vmPushSymbol( &hb_symEval );
|
||
hb_vmPush( pCondItem );
|
||
hb_vmPush( &ItemKey );
|
||
hb_vmPushLong( ( LONG ) pTag->CurKey->rec );
|
||
hb_vmDo( 2 );
|
||
fRet = hb_itemGetL( &(HB_VM_STACK.Return) );
|
||
|
||
hb_itemClear( &ItemKey );
|
||
|
||
return fRet;
|
||
}
|
||
|
||
/*
|
||
* check if Key is in top scope
|
||
*/
|
||
static BOOL hb_cdxTopScope( LPCDXTAG pTag )
|
||
{
|
||
return !pTag->topScopeKey || !pTag->topScopeKey->len ||
|
||
hb_cdxValCompare( pTag, pTag->topScopeKey->val,
|
||
pTag->topScopeKey->len,
|
||
pTag->CurKey->val,
|
||
pTag->CurKey->len, FALSE ) <= 0;
|
||
}
|
||
|
||
/*
|
||
* check if Key is in bottom scope
|
||
*/
|
||
static BOOL hb_cdxBottomScope( LPCDXTAG pTag )
|
||
{
|
||
return !pTag->bottomScopeKey || !pTag->bottomScopeKey->len ||
|
||
hb_cdxValCompare( pTag, pTag->bottomScopeKey->val,
|
||
pTag->bottomScopeKey->len,
|
||
pTag->CurKey->val,
|
||
pTag->CurKey->len, FALSE ) >= 0;
|
||
}
|
||
|
||
/*
|
||
* clear scopes
|
||
*/
|
||
static void hb_cdxTagClearScope( LPCDXTAG pTag, USHORT nScope )
|
||
{
|
||
PHB_ITEM *pScope;
|
||
LPCDXKEY *pScopeKey;
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("hb_cdxTagClearScope(%p, %hu)", pTag, nScope));
|
||
|
||
if ( nScope == 0 )
|
||
{
|
||
pScope = &pTag->topScope;
|
||
pScopeKey = &pTag->topScopeKey;
|
||
}
|
||
else
|
||
{
|
||
pScope = &pTag->bottomScope;
|
||
pScopeKey = &pTag->bottomScopeKey;
|
||
}
|
||
if ( *pScope )
|
||
{
|
||
hb_itemRelease( *pScope );
|
||
*pScope = NULL;
|
||
}
|
||
if ( *pScopeKey )
|
||
{
|
||
hb_cdxKeyFree( *pScopeKey );
|
||
*pScopeKey = NULL;
|
||
}
|
||
}
|
||
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
/*
|
||
* check internal integrity of page pool
|
||
*/
|
||
static void hb_cdxTagPoolCheck( LPCDXTAG pTag )
|
||
{
|
||
LPCDXPAGE pPage, pPrevPage;
|
||
|
||
pPage = pTag->pagePool;
|
||
pPrevPage = NULL;
|
||
while ( pPage )
|
||
{
|
||
if ( pPage->pPoolPrev != pPrevPage || pPage->TagParent != pTag )
|
||
hb_cdxErrInternal( "hb_cdxTagPoolCheck: data integrity error." );
|
||
pPrevPage = pPage;
|
||
pPage = pPage->pPoolNext;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* check if the Tag buffers was not changed without write lock
|
||
*/
|
||
static void hb_cdxTagCheckBuffers( LPCDXTAG pTag )
|
||
{
|
||
BOOL fChanged = FALSE;
|
||
|
||
hb_cdxTagPoolCheck( pTag );
|
||
if ( pTag->TagChanged )
|
||
fChanged = TRUE;
|
||
else
|
||
{
|
||
LPCDXPAGE pPage = pTag->pagePool;
|
||
while ( pPage && !fChanged )
|
||
{
|
||
fChanged = pPage->fChanged;
|
||
pPage = pPage->pPoolNext;
|
||
}
|
||
}
|
||
if ( fChanged )
|
||
hb_cdxErrInternal( "hb_cdxTagCheckBuffers: modification without write lock." );
|
||
}
|
||
|
||
/*
|
||
* check if the Index buffers was not changed without write lock
|
||
*/
|
||
static void hb_cdxIndexCheckBuffers( LPCDXINDEX pIndex )
|
||
{
|
||
LPCDXTAG pTag;
|
||
|
||
if ( pIndex->fChanged || ( pIndex->freeLst && pIndex->freeLst->fStat ) )
|
||
hb_cdxErrInternal( "hb_cdxIndexCheckBuffers: modification without write lock." );
|
||
|
||
if ( pIndex->pCompound )
|
||
hb_cdxTagCheckBuffers( pIndex->pCompound );
|
||
pTag = pIndex->TagList;
|
||
while ( pTag )
|
||
{
|
||
hb_cdxTagCheckBuffers( pTag );
|
||
pTag = pTag->pNext;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/*
|
||
* get free index page
|
||
*/
|
||
static ULONG hb_cdxIndexGetAvailPage( LPCDXINDEX pIndex, BOOL bHeader )
|
||
{
|
||
FHANDLE hFile = pIndex->hFile;
|
||
BYTE byBuf[4];
|
||
ULONG ulPos;
|
||
|
||
if ( pIndex->fReadonly )
|
||
{
|
||
hb_errInternal( 9101, "hb_cdxIndexGetAvailPage on readonly database.", "", "" );
|
||
}
|
||
if ( pIndex->fShared && !pIndex->lockWrite )
|
||
{
|
||
hb_errInternal( 9102, "hb_cdxIndexGetAvailPage on not locked index file.", "", "" );
|
||
}
|
||
|
||
if ( pIndex->freePage != 0 && pIndex->freePage != CDX_DUMMYNODE && !bHeader )
|
||
{
|
||
ulPos = pIndex->freePage;
|
||
if ( pIndex->freeLst != NULL )
|
||
{
|
||
LPCDXLIST pLst = pIndex->freeLst;
|
||
pIndex->freePage = pLst->ulAddr;
|
||
pIndex->freeLst = pLst->pNext;
|
||
hb_xfree( pLst );
|
||
}
|
||
else
|
||
{
|
||
if ( hb_fsSeek( hFile, ulPos, FS_SET ) != ulPos ||
|
||
hb_fsRead( hFile, (BYTE *) byBuf, 4 ) != 4 )
|
||
hb_errInternal( EDBF_READ, "Read index page failed.", "", "" );
|
||
pIndex->freePage = HB_GET_LE_ULONG( byBuf );
|
||
#ifdef HB_CDX_DBGUPDT
|
||
cdxReadNO++;
|
||
#endif
|
||
}
|
||
}
|
||
else
|
||
{
|
||
int iCnt = (bHeader ? 2 : 1 );
|
||
|
||
if ( pIndex->nextAvail != CDX_DUMMYNODE )
|
||
ulPos = pIndex->nextAvail;
|
||
else
|
||
ulPos = hb_fsSeek( hFile, 0, FS_END );
|
||
pIndex->nextAvail = ulPos + iCnt * CDX_PAGELEN;
|
||
|
||
/* TODO: ### */
|
||
if ( bHeader )
|
||
{
|
||
BYTE byBuf[CDX_PAGELEN];
|
||
memset( byBuf, 0, CDX_PAGELEN );
|
||
if ( hb_fsSeek( hFile, ulPos, FS_SET ) != ulPos )
|
||
hb_errInternal( EDBF_WRITE, "Write in index page failed.(1)", "", "" );
|
||
while ( iCnt-- )
|
||
{
|
||
if ( hb_fsWrite( hFile, byBuf, CDX_PAGELEN ) != CDX_PAGELEN )
|
||
hb_errInternal( EDBF_WRITE, "Write in index page failed.(2)", "", "" );
|
||
}
|
||
}
|
||
}
|
||
return ulPos;
|
||
}
|
||
|
||
/*
|
||
* free index page
|
||
*/
|
||
static void hb_cdxIndexPutAvailPage( LPCDXINDEX pIndex, ULONG ulPos, BOOL bHeader )
|
||
{
|
||
if ( ulPos != 0 && ulPos != CDX_DUMMYNODE )
|
||
{
|
||
int iCnt = (bHeader ? 2 : 1 );
|
||
LPCDXLIST pLst;
|
||
|
||
if ( pIndex->fReadonly )
|
||
hb_errInternal( 9101, "hb_cdxIndexPutAvailPage on readonly database.", "", "" );
|
||
if ( pIndex->fShared && !pIndex->lockWrite )
|
||
hb_errInternal( 9102, "hb_cdxIndexPutAvailPage on not locked index file.", "", "" );
|
||
|
||
while ( iCnt-- )
|
||
{
|
||
pLst = (LPCDXLIST) hb_xgrab( sizeof( CDXLIST ) );
|
||
pLst->ulAddr = pIndex->freePage;
|
||
pIndex->freePage = ulPos;
|
||
pLst->fStat = TRUE;
|
||
pLst->pNext = pIndex->freeLst;
|
||
pIndex->freeLst = pLst;
|
||
ulPos += CDX_PAGELEN;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* flush list of free pages into index file
|
||
*/
|
||
static void hb_cdxIndexFlushAvailPage( LPCDXINDEX pIndex )
|
||
{
|
||
LPCDXLIST pLst = pIndex->freeLst;
|
||
BYTE byPageBuf[CDX_PAGELEN];
|
||
ULONG ulPos;
|
||
|
||
if ( pIndex->fReadonly )
|
||
hb_errInternal( 9101, "hb_cdxIndexPutAvailPage on readonly database.", "", "" );
|
||
if ( pIndex->fShared && !pIndex->lockWrite )
|
||
hb_errInternal( 9102, "hb_cdxIndexPutAvailPage on not locked index file.", "", "" );
|
||
|
||
memset( byPageBuf, 0, CDX_PAGELEN );
|
||
ulPos = pIndex->freePage;
|
||
while ( pLst && pLst->fStat )
|
||
{
|
||
HB_PUT_LE_ULONG( byPageBuf, pLst->ulAddr );
|
||
if ( hb_fsSeek( pIndex->hFile, ulPos, FS_SET ) != ulPos ||
|
||
hb_fsWrite( pIndex->hFile, byPageBuf, CDX_PAGELEN ) != CDX_PAGELEN )
|
||
{
|
||
hb_errInternal( EDBF_WRITE, "Write in index page failed.", "", "" );
|
||
}
|
||
pIndex->fChanged = TRUE;
|
||
ulPos = pLst->ulAddr;
|
||
pLst->fStat = FALSE;
|
||
pLst = pLst->pNext;
|
||
#ifdef HB_CDX_DBGUPDT
|
||
cdxWriteNO++;
|
||
#endif
|
||
}
|
||
}
|
||
|
||
/*
|
||
* drop list of free pages in index file
|
||
*/
|
||
static void hb_cdxIndexDropAvailPage( LPCDXINDEX pIndex )
|
||
{
|
||
LPCDXLIST pLst;
|
||
|
||
while ( pIndex->freeLst )
|
||
{
|
||
pLst = pIndex->freeLst->pNext;
|
||
hb_xfree( pIndex->freeLst );
|
||
pIndex->freeLst = pLst;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* write index page
|
||
*/
|
||
static void hb_cdxIndexPageWrite( LPCDXINDEX pIndex, ULONG ulPos, BYTE * pBuffer,
|
||
USHORT uiSize )
|
||
{
|
||
if ( pIndex->fReadonly )
|
||
hb_errInternal( 9101, "hb_cdxIndexPageWrite on readonly database.", "", "" );
|
||
if ( pIndex->fShared && !pIndex->lockWrite )
|
||
hb_errInternal( 9102, "hb_cdxIndexPageWrite on not locked index file.", "", "" );
|
||
|
||
if ( hb_fsSeek( pIndex->hFile, ulPos, FS_SET ) != ulPos ||
|
||
hb_fsWrite( pIndex->hFile, pBuffer, uiSize ) != uiSize )
|
||
hb_errInternal( EDBF_WRITE, "Write in index page failed.", "", "" );
|
||
pIndex->fChanged = TRUE;
|
||
#ifdef HB_CDX_DBGUPDT
|
||
cdxWriteNO++;
|
||
#endif
|
||
}
|
||
|
||
/*
|
||
* read index page
|
||
*/
|
||
static void hb_cdxIndexPageRead( LPCDXINDEX pIndex, ULONG ulPos, BYTE * pBuffer,
|
||
USHORT uiSize )
|
||
{
|
||
if ( pIndex->fShared && !( pIndex->lockRead || pIndex->lockWrite ) )
|
||
hb_errInternal( 9103, "hb_cdxIndexPageRead on not locked index file.", "", "" );
|
||
|
||
if ( hb_fsSeek( pIndex->hFile, ulPos, FS_SET ) != ulPos ||
|
||
hb_fsRead( pIndex->hFile, pBuffer, uiSize ) != uiSize )
|
||
hb_errInternal( EDBF_READ, "Read index page failed.", "", "" );
|
||
#ifdef HB_CDX_DBGUPDT
|
||
cdxReadNO++;
|
||
#endif
|
||
}
|
||
|
||
/*
|
||
* check if index was updated by other process and if it was discard buffers
|
||
*/
|
||
static void hb_cdxIndexCheckVersion( LPCDXINDEX pIndex )
|
||
{
|
||
BYTE byBuf[8];
|
||
ULONG ulVer, ulFree;
|
||
|
||
if ( hb_fsSeek( pIndex->hFile, 0x04, FS_SET ) != 0x04 ||
|
||
hb_fsRead( pIndex->hFile, byBuf, 8 ) != 8 )
|
||
{
|
||
if ( pIndex->lockWrite > 0 && hb_fsSeek( pIndex->hFile, 0, FS_END ) == 0 )
|
||
memset( byBuf, 0, 8 );
|
||
else
|
||
hb_errInternal( 2155, "hb_cdxIndexCheckVersion: Read error on index heading page.", "", "" );
|
||
}
|
||
#ifdef HB_CDX_DBGUPDT
|
||
cdxReadNO++;
|
||
#endif
|
||
ulFree = HB_GET_LE_ULONG( &byBuf[0] );
|
||
ulVer = HB_GET_BE_ULONG( &byBuf[4] );
|
||
if ( !pIndex->fShared )
|
||
pIndex->ulVersion = pIndex->freePage;
|
||
else if ( ulVer != pIndex->ulVersion || ulFree != pIndex->freePage )
|
||
{
|
||
pIndex->nextAvail = CDX_DUMMYNODE;
|
||
pIndex->ulVersion = ulVer;
|
||
pIndex->freePage = ulFree;
|
||
hb_cdxIndexDiscardBuffers( pIndex );
|
||
}
|
||
/* TODO: !!! ## remove it */
|
||
//hb_cdxIndexDiscardBuffers( pIndex );
|
||
}
|
||
|
||
/*
|
||
* lock index for reading (shared lock)
|
||
*/
|
||
static BOOL hb_cdxIndexLockRead( LPCDXINDEX pIndex )
|
||
{
|
||
BOOL ret;
|
||
|
||
if ( pIndex->lockRead > 0 || pIndex->lockWrite > 0 || !pIndex->fShared )
|
||
{
|
||
pIndex->lockRead++;
|
||
return TRUE;
|
||
}
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( pIndex->lockRead != 0 )
|
||
hb_errInternal( 9105, "hb_cdxIndexLockRead: bad count of locks.", "", "" );
|
||
|
||
if ( pIndex->WrLck || pIndex->RdLck )
|
||
hb_errInternal( 9107, "hb_cdxIndexLockRead: lock failure (*)", "", "" );
|
||
pIndex->RdLck = TRUE;
|
||
#endif
|
||
|
||
ret = hb_dbfLockIdxFile( pIndex->hFile, pIndex->pArea->bLockType,
|
||
FL_LOCK | FLX_SHARED | FLX_WAIT, &pIndex->ulLockPos );
|
||
if ( !ret )
|
||
/* TODO: change into RT error dbfcdx/1038 */
|
||
hb_errInternal( 9107, "hb_cdxIndexLockRead: lock failure.", "", "" );
|
||
if ( ret )
|
||
{
|
||
pIndex->lockRead++;
|
||
hb_cdxIndexCheckVersion( pIndex );
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
/*
|
||
* lock index for writing (exclusive lock)
|
||
*/
|
||
static BOOL hb_cdxIndexLockWrite( LPCDXINDEX pIndex )
|
||
{
|
||
BOOL ret;
|
||
|
||
if ( pIndex->lockRead )
|
||
hb_errInternal( 9105, "hb_cdxIndexLockRead: writeLock after readLock.", "", "" );
|
||
if ( pIndex->lockWrite > 0 )
|
||
{
|
||
pIndex->lockWrite++;
|
||
return TRUE;
|
||
}
|
||
if ( pIndex->lockWrite != 0 )
|
||
hb_errInternal( 9105, "hb_cdxIndexLockWrite: bad count of locks.", "", "" );
|
||
|
||
if ( !pIndex->fShared )
|
||
ret = TRUE;
|
||
else
|
||
{
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( pIndex->WrLck || pIndex->RdLck )
|
||
hb_errInternal( 9107, "hb_cdxIndexLockWrite: lock failure (*)", "", "" );
|
||
pIndex->WrLck = TRUE;
|
||
#endif
|
||
ret = hb_dbfLockIdxFile( pIndex->hFile, pIndex->pArea->bLockType,
|
||
FL_LOCK | FLX_EXCLUSIVE | FLX_WAIT, &pIndex->ulLockPos );
|
||
}
|
||
if ( !ret )
|
||
/* TODO: change into RT error dbfcdx/1038 */
|
||
hb_errInternal( 9107, "hb_cdxIndexLockWrite: lock failure.", "", "" );
|
||
|
||
if ( ret )
|
||
{
|
||
pIndex->lockWrite++;
|
||
if ( pIndex->fShared || pIndex->nextAvail == CDX_DUMMYNODE )
|
||
hb_cdxIndexCheckVersion( pIndex );
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
/*
|
||
* remove index read lock (shared lock)
|
||
*/
|
||
static BOOL hb_cdxIndexUnLockRead( LPCDXINDEX pIndex )
|
||
{
|
||
pIndex->lockRead--;
|
||
if ( pIndex->lockRead < 0 )
|
||
{
|
||
hb_errInternal( 9106, "hb_cdxIndexUnLockRead: bad count of locks.", "", "" );
|
||
}
|
||
if ( pIndex->lockRead || pIndex->lockWrite )
|
||
{
|
||
return TRUE;
|
||
}
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxIndexCheckBuffers( pIndex );
|
||
#endif
|
||
|
||
hb_cdxIndexPoolFree( pIndex, CDX_PAGECACHESIZE );
|
||
|
||
if ( pIndex->fShared )
|
||
{
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( pIndex->WrLck || ! pIndex->RdLck )
|
||
hb_errInternal( 9108, "hb_cdxIndexUnLockRead: unlock error (*)", "", "" );
|
||
pIndex->RdLck = FALSE;
|
||
#endif
|
||
if ( !hb_dbfLockIdxFile( pIndex->hFile, pIndex->pArea->bLockType, FL_UNLOCK, &pIndex->ulLockPos ) )
|
||
{
|
||
hb_errInternal( 9108, "hb_cdxIndexUnLockRead: unlock error.", "", "" );
|
||
}
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* remove index write lock (exclusive lock)
|
||
*/
|
||
static BOOL hb_cdxIndexUnLockWrite( LPCDXINDEX pIndex )
|
||
{
|
||
if ( pIndex->lockWrite > 1 )
|
||
{
|
||
pIndex->lockWrite--;
|
||
return TRUE;
|
||
}
|
||
|
||
if ( pIndex->lockWrite < 1 )
|
||
{
|
||
hb_errInternal( 9106, "hb_cdxIndexUnLockRead: bad count of locks.", "", "" );
|
||
}
|
||
if ( pIndex->lockRead )
|
||
{
|
||
hb_errInternal( 9105, "hb_cdxIndexUnLockWrite: writeUnLock before readUnLock.", "", "" );
|
||
}
|
||
|
||
hb_cdxIndexFlushBuffers( pIndex );
|
||
hb_cdxIndexPoolFree( pIndex, CDX_PAGECACHESIZE );
|
||
|
||
pIndex->lockWrite--;
|
||
if ( pIndex->fShared )
|
||
{
|
||
if ( pIndex->fChanged )
|
||
{
|
||
BYTE byBuf[8];
|
||
(pIndex->ulVersion)++;
|
||
HB_PUT_LE_ULONG( &byBuf[0], pIndex->freePage );
|
||
HB_PUT_BE_ULONG( &byBuf[4], pIndex->ulVersion );
|
||
if ( hb_fsSeek( pIndex->hFile, 0x04, FS_SET ) != 0x04 ||
|
||
hb_fsWrite( pIndex->hFile, byBuf, 8) != 8 )
|
||
{
|
||
hb_errInternal( EDBF_WRITE, "Write in index page failed (ver)", "", "" );
|
||
}
|
||
pIndex->fChanged = FALSE;
|
||
}
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( ! pIndex->WrLck || pIndex->RdLck )
|
||
hb_errInternal( 9108, "hb_cdxIndexUnLockWrite: unlock error (*)", "", "" );
|
||
pIndex->WrLck = FALSE;
|
||
#endif
|
||
if ( !hb_dbfLockIdxFile( pIndex->hFile, pIndex->pArea->bLockType, FL_UNLOCK, &pIndex->ulLockPos ) )
|
||
{
|
||
hb_errInternal( 9108, "hb_cdxIndexUnLockWrite: unlock error.", "", "" );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ( pIndex->ulVersion != pIndex->freePage )
|
||
{
|
||
BYTE byBuf[4];
|
||
HB_PUT_LE_ULONG( &byBuf[0], pIndex->freePage );
|
||
if ( hb_fsSeek( pIndex->hFile, 0x04, FS_SET ) != 0x04 ||
|
||
hb_fsWrite( pIndex->hFile, byBuf, 4) != 4 )
|
||
{
|
||
hb_errInternal( EDBF_WRITE, "Write in index page failed (ver.ex)", "", "" );
|
||
}
|
||
pIndex->ulVersion = pIndex->freePage;
|
||
#ifdef HB_CDX_DBGUPDT
|
||
cdxWriteNO++;
|
||
#endif
|
||
}
|
||
pIndex->fChanged = FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* discard all pages in cache (TagClose and TagPoolFree for all Tags)
|
||
*/
|
||
static void hb_cdxIndexDiscardBuffers( LPCDXINDEX pIndex )
|
||
{
|
||
LPCDXTAG pTag;
|
||
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxIndexCheckBuffers( pIndex );
|
||
#endif
|
||
|
||
hb_cdxIndexDropAvailPage( pIndex );
|
||
if ( pIndex->pCompound )
|
||
{
|
||
hb_cdxTagClose( pIndex->pCompound );
|
||
hb_cdxTagPoolFree( pIndex->pCompound, 0 );
|
||
pIndex->pCompound->fRePos = TRUE;
|
||
if ( pIndex->pCompound->CurKey )
|
||
pIndex->pCompound->CurKey->rec = 0;
|
||
}
|
||
pTag = pIndex->TagList;
|
||
while ( pTag )
|
||
{
|
||
hb_cdxTagClose( pTag );
|
||
hb_cdxTagPoolFree( pTag, 0 );
|
||
pTag->fRePos = TRUE;
|
||
if ( pTag->CurKey && !pTag->Custom )
|
||
pTag->CurKey->rec = 0;
|
||
pTag = pTag->pNext;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* write all changed pages in cache (pagePool, pages in Tags and Tag Header)
|
||
*/
|
||
static void hb_cdxIndexFlushBuffers( LPCDXINDEX pIndex )
|
||
{
|
||
LPCDXTAG pTag;
|
||
|
||
if ( pIndex->pCompound )
|
||
{
|
||
hb_cdxTagPoolFlush( pIndex->pCompound );
|
||
if ( pIndex->pCompound->TagChanged )
|
||
hb_cdxTagHeaderStore( pIndex->pCompound );
|
||
}
|
||
pTag = pIndex->TagList;
|
||
while ( pTag )
|
||
{
|
||
hb_cdxTagPoolFlush( pTag );
|
||
if ( pTag->TagChanged )
|
||
hb_cdxTagHeaderStore( pTag );
|
||
pTag = pTag->pNext;
|
||
}
|
||
hb_cdxIndexFlushAvailPage( pIndex );
|
||
}
|
||
|
||
/*
|
||
* free cached pages of index file
|
||
*/
|
||
static void hb_cdxIndexPoolFree( LPCDXINDEX pIndex, int nPagesLeft )
|
||
{
|
||
LPCDXTAG pTag;
|
||
|
||
if ( pIndex->pCompound )
|
||
{
|
||
hb_cdxTagPoolFree( pIndex->pCompound, nPagesLeft );
|
||
}
|
||
pTag = pIndex->TagList;
|
||
while ( pTag )
|
||
{
|
||
hb_cdxTagPoolFree( pTag, nPagesLeft );
|
||
pTag = pTag->pNext;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* get key value ptr from index page
|
||
*/
|
||
static BYTE * hb_cdxPageGetKeyVal( LPCDXPAGE pPage, SHORT iKey )
|
||
{
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( iKey < 0 || iKey >= pPage->iKeys )
|
||
hb_cdxErrInternal( "hb_cdxPageGetKeyVal: wrong iKey index." );
|
||
#endif
|
||
if ( pPage->pKeyBuf )
|
||
return &pPage->pKeyBuf[ iKey * ( pPage->TagParent->uiLen + 6 ) ];
|
||
else if ( pPage->PageType & CDX_NODE_LEAF )
|
||
{
|
||
SHORT iPos, iLen, iTmp, iTrl, iDup;
|
||
BYTE bTrail;
|
||
|
||
iLen = pPage->TagParent->uiLen;
|
||
bTrail = ( BYTE ) ( pPage->TagParent->uiType == 'C' ? ' ' : '\0' );
|
||
if ( iKey < pPage->bufKeyNum - 1 )
|
||
pPage->bufKeyNum = 0;
|
||
if ( pPage->bufKeyNum == 0 )
|
||
{
|
||
pPage->bufKeyPos = CDX_EXT_FREESPACE;
|
||
pPage->bufKeyLen = iLen;
|
||
}
|
||
while ( pPage->bufKeyNum <= iKey )
|
||
{
|
||
iPos = pPage->bufKeyNum * pPage->ReqByte;
|
||
iTmp = HB_GET_LE_USHORT( &pPage->node.extNode.keyPool[ iPos + pPage->ReqByte - 2 ] ) >>
|
||
( 16 - pPage->TCBits - pPage->DCBits );
|
||
iDup = ( pPage->bufKeyNum == 0 ) ? 0 : ( iTmp & pPage->DCMask );
|
||
iTrl = ( iTmp >> pPage->DCBits ) & pPage->TCMask;
|
||
if ( ( iTmp = iLen - iDup - iTrl ) > 0 )
|
||
{
|
||
pPage->bufKeyPos -= iTmp;
|
||
memcpy( &pPage->bufKeyVal[ iDup ],
|
||
&pPage->node.extNode.keyPool[ pPage->bufKeyPos ], iTmp );
|
||
}
|
||
#ifdef HB_CDX_DBGCODE
|
||
else if ( iTmp < 0 )
|
||
{
|
||
printf("\r\npPage->Page=%lx, iLen=%d, iDup=%d, iTrl=%d", pPage->Page, iLen, iDup, iTrl); fflush(stdout);
|
||
hb_cdxErrInternal( "hb_cdxPageGetKeyVal: index corrupted." );
|
||
}
|
||
#endif
|
||
if ( iTrl > 0 && ( iTmp = pPage->bufKeyLen - iLen + iTrl ) > 0 )
|
||
memset( &pPage->bufKeyVal[ iLen - iTrl ], bTrail, iTmp );
|
||
pPage->bufKeyLen = iLen - iTrl;
|
||
pPage->bufKeyNum++;
|
||
}
|
||
return pPage->bufKeyVal;
|
||
}
|
||
else
|
||
return &pPage->node.intNode.keyPool[ iKey * ( pPage->TagParent->uiLen + 8 ) ];
|
||
}
|
||
|
||
/*
|
||
* get record number from index page
|
||
*/
|
||
static ULONG hb_cdxPageGetKeyRec( LPCDXPAGE pPage, SHORT iKey )
|
||
{
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( iKey < 0 || iKey >= pPage->iKeys )
|
||
hb_cdxErrInternal( "hb_cdxPageGetKeyRec: wrong iKey index." );
|
||
#endif
|
||
if ( pPage->pKeyBuf )
|
||
return HB_GET_LE_ULONG( &pPage->pKeyBuf[ ( iKey + 1 ) * ( pPage->TagParent->uiLen + 6 ) - 6 ] );
|
||
else if ( pPage->PageType & CDX_NODE_LEAF )
|
||
return HB_GET_LE_ULONG( &pPage->node.extNode.keyPool[ iKey * pPage->ReqByte ] ) & pPage->RNMask;
|
||
else
|
||
return HB_GET_BE_ULONG( &pPage->node.intNode.keyPool[
|
||
( iKey + 1 ) * ( pPage->TagParent->uiLen + 8 ) - 8 ] );
|
||
}
|
||
|
||
/*
|
||
* get child page number from interrior index page
|
||
*/
|
||
static ULONG hb_cdxPageGetKeyPage( LPCDXPAGE pPage, SHORT iKey )
|
||
{
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( iKey < 0 || iKey >= pPage->iKeys )
|
||
hb_cdxErrInternal( "hb_cdxPageGetKeyPage: wrong iKey index." );
|
||
if ( pPage->PageType & CDX_NODE_LEAF )
|
||
hb_cdxErrInternal( "hb_cdxPageGetKeyPage: page is a leaf." );
|
||
#endif
|
||
return HB_GET_BE_ULONG( &pPage->node.intNode.keyPool[
|
||
( iKey + 1 ) * ( pPage->TagParent->uiLen + 8 ) - 4 ] );
|
||
}
|
||
|
||
#if 0
|
||
/*
|
||
* get key from uncompressed page
|
||
*/
|
||
static LPCDXKEY hb_cdxPageGetKey( LPCDXPAGE pPage, SHORT iKey, LPCDXKEY pKey )
|
||
{
|
||
return hb_cdxKeyPut( pKey,
|
||
hb_cdxPageGetKeyVal( pPage, iKey ),
|
||
pPage->TagParent->uiLen,
|
||
hb_cdxPageGetKeyRec( pPage, iKey ) );
|
||
}
|
||
#endif
|
||
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
/*
|
||
* check if keys are sorted in proper order
|
||
*/
|
||
static void hb_cdxPageCheckKeys( LPCDXPAGE pPage )
|
||
{
|
||
SHORT i, K, iLen = pPage->TagParent->uiLen;
|
||
ULONG ulRec, ulRecPrev;
|
||
BYTE * pbVal, pbValPrev[CDX_MAXKEY];
|
||
|
||
if ( pPage->iKeys > 1 )
|
||
{
|
||
pPage->bufKeyNum = 0;
|
||
pbVal = hb_cdxPageGetKeyVal( pPage, 0 );
|
||
ulRec = hb_cdxPageGetKeyRec( pPage, 0 );
|
||
for ( i = 1; i < pPage->iKeys; i++ )
|
||
{
|
||
memcpy( pbValPrev, pbVal, iLen );
|
||
ulRecPrev = ulRec;
|
||
pbVal = hb_cdxPageGetKeyVal( pPage, i );
|
||
ulRec = hb_cdxPageGetKeyRec( pPage, i );
|
||
K = hb_cdxValCompare( pPage->TagParent,
|
||
pbValPrev, iLen,
|
||
pbVal, iLen, TRUE );
|
||
if ( K > 0 || ( K == 0 && ulRecPrev >= ulRec ) )
|
||
{
|
||
printf( "\r\nikey=%d, pPage->iKeys=%d, K=%d, ulRecPrev=%ld, ulRec=%ld",
|
||
i, pPage->iKeys, K, ulRecPrev, ulRec );fflush(stdout);
|
||
printf( "\r\npbValPrev=[%s] pbVal=[%s], [%d], pPage->pKeyBuf=%p, pPage->iCurKey=%d",
|
||
pbValPrev, pbVal, memcmp( pbValPrev, pbVal, iLen ),
|
||
pPage->pKeyBuf, pPage->iCurKey );fflush(stdout);
|
||
hb_cdxErrInternal( "hb_cdxPageCheckKeys: index corrupted." );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Check decoded leaf page if all trailing and duplicate characters are set
|
||
*/
|
||
static void hb_cdxPageCheckDupTrl( LPCDXPAGE pPage, BYTE * pKeyBuf, SHORT iKeys )
|
||
{
|
||
SHORT iNum = pPage->TagParent->uiLen, iKey, iPos;
|
||
SHORT iLen = iNum + 6;
|
||
BYTE bDup, bTrl;
|
||
BYTE bTrail = ( pPage->TagParent->uiType == 'C' ) ? ' ' : '\0';
|
||
BOOL bErr = FALSE;
|
||
|
||
for ( iKey = 0; iKey < iKeys; iKey++ )
|
||
{
|
||
iPos = iKey * iLen;
|
||
bTrl = bDup = 0;
|
||
while ( bTrl < iNum && pKeyBuf[ iPos + iNum - bTrl - 1 ] == bTrail )
|
||
++bTrl;
|
||
if ( iKey > 0 )
|
||
{
|
||
SHORT iMax = iNum - /* bTrl; */ HB_MAX( pKeyBuf[ iPos - 1 ], bTrl );
|
||
while ( bDup < iMax && pKeyBuf[ iPos + bDup ] ==
|
||
pKeyBuf[ iPos - iLen + bDup ] )
|
||
++bDup;
|
||
}
|
||
if ( bTrl != pKeyBuf[ iPos + iNum + 5 ] )
|
||
{
|
||
printf("\r\nbTrl=%d, keybuf->bTrl=%d, iKey=%d/%d\r\n", bTrl, pKeyBuf[ iPos + iNum + 5 ], iKey, iKeys );
|
||
fflush(stdout);
|
||
bErr = TRUE;
|
||
}
|
||
if ( bDup != ( iKey == 0 ? 0 : pKeyBuf[ iPos + iNum + 4 ] ) )
|
||
{
|
||
printf("\r\nbDup=%d, keybuf->bDup=%d, iKey=%d/%d\r\n", bDup, pKeyBuf[ iPos + iNum + 4 ], iKey, iKeys );
|
||
fflush(stdout);
|
||
bErr = TRUE;
|
||
}
|
||
if ( iKey > 0 )
|
||
{
|
||
SHORT K;
|
||
K = hb_cdxValCompare( pPage->TagParent,
|
||
&pKeyBuf[ iPos - iLen ], iNum,
|
||
&pKeyBuf[ iPos ], iNum, TRUE );
|
||
if ( K > 0 || ( K == 0 &&
|
||
HB_GET_LE_ULONG( &pKeyBuf[ iPos + iNum - iLen ] ) >=
|
||
HB_GET_LE_ULONG( &pKeyBuf[ iPos + iNum ] ) ) )
|
||
{
|
||
printf( "\r\nikey=%d, iKeys=%d, K=%d, ulRecPrev=%ld, ulRec=%ld",
|
||
iKey, iKeys, K,
|
||
HB_GET_LE_ULONG( &pKeyBuf[ iPos + iNum - iLen ] ),
|
||
HB_GET_LE_ULONG( &pKeyBuf[ iPos + iNum ] ) );
|
||
printf( "\r\npbValPrev=[%s] pbVal=[%s], [%d], pKeyBuf=%p",
|
||
&pKeyBuf[ iPos - iLen ], &pKeyBuf[ iPos ],
|
||
memcmp( &pKeyBuf[ iPos - iLen ], &pKeyBuf[ iPos ], iNum ),
|
||
pKeyBuf );
|
||
fflush(stdout);
|
||
bErr = TRUE;
|
||
}
|
||
}
|
||
}
|
||
if ( bErr )
|
||
hb_cdxErrInternal( "hb_cdxPageCheckDupTrl: index corrupted." );
|
||
}
|
||
#endif
|
||
|
||
/*
|
||
* put record and duplicate + trailing counters into leaf page
|
||
*/
|
||
static void hb_cdxSetLeafRecord( BYTE *pDst, ULONG ulRec, int iDup, int iTrl,
|
||
int iReq, int iDCbits, int iTCbits )
|
||
{
|
||
int i;
|
||
USHORT usBit;
|
||
|
||
usBit = ( ( iTrl << iDCbits ) | iDup ) << ( 16 - iTCbits - iDCbits );
|
||
for ( i = 0; i < iReq; i++, ulRec >>= 8 )
|
||
{
|
||
if ( i < iReq - 2 )
|
||
pDst[ i ] = ulRec & 0xff;
|
||
else if ( i == iReq - 2 )
|
||
pDst[ i ] = ( ulRec & 0xff ) | ( usBit & 0xff );
|
||
else
|
||
pDst[ i ] = ( ulRec & 0xff ) | ( ( usBit >> 8 ) & 0xff );
|
||
}
|
||
}
|
||
|
||
/*
|
||
* encode keys in buffer into cdx leaf node
|
||
*/
|
||
static void hb_cdxPageLeafEncode( LPCDXPAGE pPage, BYTE * pKeyBuf, SHORT iKeys )
|
||
{
|
||
int iKey, iTrl, iDup, iReq, iTmp, iNum, iLen;
|
||
BYTE *pKeyPos, *pRecPos, *pSrc;
|
||
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( ( pPage->PageType & CDX_NODE_LEAF ) == 0 )
|
||
{
|
||
printf("\r\npPage->Page=%lx. left=%lx, right=%lx",
|
||
pPage->Page, pPage->Left, pPage->Right); fflush(stdout);
|
||
hb_cdxErrInternal( "hb_cdxPageLeafEncode: page is not a leaf." );
|
||
}
|
||
#endif
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
if ( ! pKeyBuf )
|
||
hb_cdxErrInternal( "hb_cdxPageLeafEncode: page has no buffer." );
|
||
hb_cdxPageCheckDupTrl( pPage, pKeyBuf, iKeys );
|
||
#endif
|
||
iNum = pPage->TagParent->uiLen;
|
||
iLen = iNum + 6;
|
||
iReq = pPage->ReqByte;
|
||
pKeyPos = &pPage->node.extNode.keyPool[ CDX_EXT_FREESPACE ];
|
||
pRecPos = &pPage->node.extNode.keyPool[ 0 ];
|
||
pSrc = &pKeyBuf[ 0 ];
|
||
for ( iKey = 0; iKey < iKeys; iKey++, pSrc += iLen, pRecPos += iReq )
|
||
{
|
||
iDup = pSrc[ iNum + 4 ];
|
||
iTrl = pSrc[ iNum + 5 ];
|
||
iTmp = iNum - iTrl - iDup;
|
||
hb_cdxSetLeafRecord( pRecPos, HB_GET_LE_ULONG( &pSrc[ iNum ] ), iDup, iTrl,
|
||
iReq, pPage->DCBits, pPage->TCBits );
|
||
if ( iTmp > 0 )
|
||
{
|
||
pKeyPos -= iTmp;
|
||
memcpy( pKeyPos, &pSrc[ iDup ], iTmp );
|
||
}
|
||
#ifdef HB_CDX_DBGCODE
|
||
else if ( iTmp < 0 )
|
||
{
|
||
printf("\r\n[%s][%s]", pSrc - iLen, pSrc);
|
||
printf("\r\npPage->Page=0x%lx, iKey=%d, iNum=%d, iDup=%d, iTrl=%d", pPage->Page, iKey, iNum, iDup, iTrl); fflush(stdout);
|
||
hb_cdxErrInternal( "hb_cdxPageLeafEncode: index corrupted." );
|
||
}
|
||
#endif
|
||
}
|
||
if ( pRecPos < pKeyPos )
|
||
memset( pRecPos, 0, pKeyPos - pRecPos );
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( pKeyPos - pRecPos != pPage->iFree )
|
||
{
|
||
printf("\r\nPage=0x%lx, calc=%d, iFree=%d, req=%d, keys=%d, keyLen=%d\r\n",
|
||
pPage->Page, pKeyPos - pRecPos, pPage->iFree, pPage->ReqByte, iKeys, iNum );
|
||
fflush(stdout);
|
||
hb_cdxErrInternal( "hb_cdxPageLeafEncode: FreeSpace calculated wrong!." );
|
||
}
|
||
if ( pPage->iFree < 0 )
|
||
hb_cdxErrInternal( "hb_cdxPageLeafEncode: FreeSpace calculated wrong!!." );
|
||
#endif
|
||
pPage->iKeys = iKeys;
|
||
pPage->fChanged = TRUE;
|
||
pPage->bufKeyNum = 0;
|
||
#ifdef HB_CDX_DBGCODE_EXT_EXT
|
||
{
|
||
BYTE * pKeyBf = pPage->pKeyBuf;
|
||
pPage->pKeyBuf = NULL;
|
||
hb_cdxPageCheckKeys( pPage );
|
||
pPage->pKeyBuf = pKeyBf;
|
||
}
|
||
hb_cdxPageCheckKeys( pPage );
|
||
hb_cdxPageCheckDupTrl( pPage, pKeyBuf, pPage->iKeys );
|
||
#endif
|
||
}
|
||
|
||
/*
|
||
* decode keys in page into buffer
|
||
*/
|
||
static void hb_cdxPageLeafDecode( LPCDXPAGE pPage, BYTE * pKeyBuf )
|
||
{
|
||
int iKey, iTmp, iBits, iDup, iTrl, iNew, iReq, iLen = pPage->TagParent->uiLen;
|
||
BYTE *pDst, *pSrc, *pRec, *pTmp, bTrail = ( pPage->TagParent->uiType == 'C' ) ? ' ' : '\0';
|
||
ULONG ulRec;
|
||
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( ( pPage->PageType & CDX_NODE_LEAF ) == 0 )
|
||
{
|
||
printf("\r\npPage->Page=%lx", pPage->Page); fflush(stdout);
|
||
hb_cdxErrInternal( "hb_cdxPageLeafDecode: page is not a leaf." );
|
||
}
|
||
#endif
|
||
iBits = ( 16 - pPage->TCBits - pPage->DCBits );
|
||
pDst = pKeyBuf;
|
||
pSrc = &pPage->node.extNode.keyPool[ CDX_EXT_FREESPACE ];
|
||
pRec = pPage->node.extNode.keyPool;
|
||
iReq = pPage->ReqByte;
|
||
for ( iKey = 0; iKey < pPage->iKeys; iKey++, pRec += iReq )
|
||
{
|
||
pTmp = &pRec[ iReq - 2 ];
|
||
iTmp = HB_GET_LE_USHORT( pTmp ) >> iBits;
|
||
iDup = ( iKey == 0 ) ? 0 : ( iTmp & pPage->DCMask );
|
||
iTrl = ( iTmp >> pPage->DCBits ) & pPage->TCMask;
|
||
iNew = iLen - iDup - iTrl;
|
||
if ( iDup > 0 )
|
||
{
|
||
memcpy( pDst, pDst - iLen - 6, iDup );
|
||
pDst += iDup;
|
||
}
|
||
if ( iNew > 0 )
|
||
{
|
||
pSrc -= iNew;
|
||
memcpy( pDst, pSrc, iNew );
|
||
pDst += iNew;
|
||
}
|
||
#ifdef HB_CDX_DBGCODE
|
||
else if ( iNew < 0 )
|
||
{
|
||
printf("\r\npPage->Page=%lx, iLen=%d, iDup=%d, iTrl=%d", pPage->Page, iLen, iDup, iTrl); fflush(stdout);
|
||
hb_cdxErrInternal( "hb_cdxPageLeafDecode: index corrupted." );
|
||
}
|
||
#endif
|
||
if ( iTrl > 0 )
|
||
{
|
||
memset( pDst, bTrail, iTrl );
|
||
pDst += iTrl;
|
||
}
|
||
ulRec = HB_GET_LE_ULONG( pRec ) & pPage->RNMask;
|
||
HB_PUT_LE_ULONG( pDst, ulRec );
|
||
pDst += 4;
|
||
*(pDst++) = ( BYTE ) iDup;
|
||
*(pDst++) = ( BYTE ) iTrl;
|
||
}
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
{
|
||
BOOL fChg = pPage->fChanged;
|
||
hb_cdxPageLeafEncode( pPage, pKeyBuf, pPage->iKeys );
|
||
pPage->fChanged = fChg;
|
||
}
|
||
#endif
|
||
}
|
||
|
||
/*
|
||
* init space leaf page
|
||
*/
|
||
static void hb_cdxPageLeafInitSpace( LPCDXPAGE pPage )
|
||
{
|
||
SHORT iLen = pPage->TagParent->uiLen;
|
||
BYTE bBits;
|
||
|
||
for ( bBits = 0; iLen; bBits++, iLen >>= 1 );
|
||
pPage->ReqByte = 3;
|
||
pPage->RNBits = 24 - ( bBits << 1 );
|
||
pPage->DCBits = pPage->TCBits = bBits;
|
||
pPage->DCMask = pPage->TCMask = (BYTE) HB_CDXBITMASK( bBits );
|
||
pPage->RNMask = HB_CDXBITMASK( pPage->RNBits );
|
||
pPage->iFree = CDX_EXT_FREESPACE;
|
||
}
|
||
|
||
/*
|
||
* calculate the size of keys stored in buffer, return
|
||
* the nymber of keys wich can be stored in the page
|
||
*/
|
||
static void hb_cdxPageCalcLeafSpace( LPCDXPAGE pPage, BYTE * pKeyBuf, SHORT iKeys )
|
||
{
|
||
SHORT iNum = pPage->TagParent->uiLen, iKey, iSize;
|
||
SHORT iLen = iNum + 6;
|
||
BYTE bDup, bTrl, ReqByte, *bPtr;
|
||
ULONG ulRec, RNMask;
|
||
|
||
hb_cdxPageLeafInitSpace( pPage );
|
||
pPage->iKeys = 0;
|
||
RNMask = pPage->RNMask;
|
||
ReqByte = pPage->ReqByte;
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxPageCheckDupTrl( pPage, pKeyBuf, iKeys );
|
||
#endif
|
||
for ( iKey = 0; iKey < iKeys; iKey++ )
|
||
{
|
||
bPtr = &pKeyBuf[ iKey * iLen + iNum ];
|
||
bTrl = bPtr[ 5 ];
|
||
if ( iKey == 0 )
|
||
bDup = bPtr[ 4 ] = 0;
|
||
else
|
||
bDup = bPtr[ 4 ];
|
||
ulRec = HB_GET_LE_ULONG( bPtr );
|
||
iSize = ReqByte + iNum - bTrl - bDup;
|
||
if ( ulRec > RNMask )
|
||
{
|
||
BYTE RNBits = pPage->RNBits;
|
||
while ( ulRec > RNMask )
|
||
{
|
||
ReqByte++;
|
||
RNBits += 8;
|
||
RNMask = ( RNMask << 8 ) | 0xFF;
|
||
iSize += ( iKey + 1 );
|
||
}
|
||
if ( iSize > pPage->iFree )
|
||
break;
|
||
#ifdef HB_CDX_DSPDBG_INFO_X
|
||
printf("\r\npPage->Page=%lx, ulRec=%lx, RNMask=%lx/%lx, RNBits=%d/%d, DCB=%d, TCB=%d (%lx), iKey=%d/%d",
|
||
pPage->Page, ulRec, RNMask, pPage->RNMask, RNBits, pPage->RNBits,
|
||
pPage->DCBits, pPage->TCBits, HB_CDXBITMASK( RNBits ), iKey, iKeys);
|
||
fflush(stdout);
|
||
#endif
|
||
pPage->RNMask = RNMask;
|
||
pPage->RNBits = RNBits;
|
||
pPage->ReqByte = ReqByte;
|
||
}
|
||
else if ( iSize > pPage->iFree )
|
||
break;
|
||
pPage->iFree -= iSize;
|
||
pPage->iKeys++;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* remove key from page
|
||
*/
|
||
static int hb_cdxPageLeafDelKey( LPCDXPAGE pPage )
|
||
{
|
||
SHORT iKey = pPage->iCurKey, iLen = pPage->TagParent->uiLen + 6, iSpc;
|
||
int iRet = 0;
|
||
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( ( pPage->PageType & CDX_NODE_LEAF ) == 0 )
|
||
hb_cdxErrInternal( "hb_cdxPageLeafDelKey: page is not a leaf." );
|
||
if ( iKey < 0 || iKey >= pPage->iKeys )
|
||
hb_cdxErrInternal( "hb_cdxPageLeafDelKey: wrong iKey index." );
|
||
#endif
|
||
if ( !pPage->pKeyBuf )
|
||
{
|
||
BYTE *pKeyBuf = (BYTE *) hb_xgrab( ( pPage->iKeys ) * iLen );
|
||
hb_cdxPageLeafDecode( pPage, pKeyBuf );
|
||
pPage->pKeyBuf = pKeyBuf;
|
||
}
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf("\r\ndelkey: Page=%lx, iKey=%d/%d, rec=%ld",
|
||
pPage->Page, iKey, pPage->iKeys,
|
||
HB_GET_LE_ULONG( &pPage->pKeyBuf[ ( iKey + 1 ) * iLen - 6 ] ));
|
||
fflush(stdout);
|
||
#endif
|
||
iSpc = pPage->ReqByte + pPage->TagParent->uiLen -
|
||
pPage->pKeyBuf[ ( iKey + 1 ) * iLen - 2 ] -
|
||
pPage->pKeyBuf[ ( iKey + 1 ) * iLen - 1 ];
|
||
if ( iKey < pPage->iKeys - 1 )
|
||
{
|
||
SHORT iPos = ( iKey + 2 ) * iLen - 2, iDup = 0;
|
||
iSpc -= pPage->pKeyBuf[ iPos ];
|
||
if ( iKey > 0 )
|
||
{
|
||
SHORT iPrev = ( iKey - 1 ) * iLen, iNext = ( iKey + 1 ) * iLen,
|
||
iNum = pPage->TagParent->uiLen;
|
||
iNum -= /* pPage->pKeyBuf[ iNext + iNum + 5 ]; */
|
||
HB_MAX( pPage->pKeyBuf[ iNext + iLen - 1 ],
|
||
pPage->pKeyBuf[ iPrev + iLen - 1 ] );
|
||
iDup = HB_MIN( pPage->pKeyBuf[ iPos ],
|
||
pPage->pKeyBuf[ iNext - 2] );
|
||
if ( iDup > iNum )
|
||
{
|
||
iDup = iNum;
|
||
}
|
||
else
|
||
{
|
||
while ( iDup < iNum && pPage->pKeyBuf[ iPrev + iDup ] ==
|
||
pPage->pKeyBuf[ iNext + iDup ] )
|
||
++iDup;
|
||
}
|
||
}
|
||
iSpc += ( pPage->pKeyBuf[ iPos ] = ( BYTE ) iDup );
|
||
}
|
||
pPage->iFree += iSpc;
|
||
if ( --pPage->iKeys > iKey )
|
||
{
|
||
memmove( &pPage->pKeyBuf[ iKey * iLen ],
|
||
&pPage->pKeyBuf[ ( iKey + 1 ) * iLen ],
|
||
( pPage->iKeys - iKey ) * iLen );
|
||
}
|
||
pPage->fBufChanged = pPage->fChanged = TRUE;
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxPageCheckKeys( pPage );
|
||
hb_cdxPageCheckDupTrl( pPage, pPage->pKeyBuf, pPage->iKeys );
|
||
#endif
|
||
if ( iKey >= pPage->iKeys )
|
||
iRet |= NODE_NEWLASTKEY;
|
||
if ( pPage->iKeys == 0 )
|
||
iRet |= NODE_JOIN;
|
||
/* if ( pPage->iFree >= CDX_EXT_FREESPACE / 2 ) */
|
||
if ( pPage->iFree >= pPage->ReqByte )
|
||
iRet |= NODE_BALANCE;
|
||
return iRet;
|
||
}
|
||
|
||
/*
|
||
* add key to page at current position
|
||
*/
|
||
static int hb_cdxPageLeafAddKey( LPCDXPAGE pPage, LPCDXKEY pKey )
|
||
{
|
||
SHORT iKey, iNum = pPage->TagParent->uiLen;
|
||
SHORT iLen = iNum + 6, iSpc, iTrl, iDup, iMax, iPos;
|
||
BYTE bTrail = ( pPage->TagParent->uiType == 'C' ) ? ' ' : '\0';
|
||
int iRet = 0;
|
||
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf("\r\naddkey: Page=%lx, iKey=%d/%d, rec=%ld",
|
||
pPage->Page, pPage->iCurKey, pPage->iKeys, pKey->rec);
|
||
fflush(stdout);
|
||
#endif
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( ( pPage->PageType & CDX_NODE_LEAF ) == 0 )
|
||
hb_cdxErrInternal( "hb_cdxPageLeafAddKey: page is not a leaf." );
|
||
if ( pPage->iCurKey < 0 || pPage->iCurKey > pPage->iKeys )
|
||
hb_cdxErrInternal( "hb_cdxPageLeafAddKey: wrong iKey index." );
|
||
#endif
|
||
if ( !pPage->pKeyBuf )
|
||
{
|
||
BYTE *pKeyBuf = (BYTE *) hb_xgrab( ( pPage->iKeys + 1 ) * iLen );
|
||
hb_cdxPageLeafDecode( pPage, pKeyBuf );
|
||
pPage->pKeyBuf = pKeyBuf;
|
||
}
|
||
else
|
||
{
|
||
pPage->pKeyBuf = (BYTE*) hb_xrealloc( pPage->pKeyBuf, ( pPage->iKeys + 1 ) * iLen );
|
||
}
|
||
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxPageCheckKeys( pPage );
|
||
hb_cdxPageCheckDupTrl( pPage, pPage->pKeyBuf, pPage->iKeys );
|
||
#endif
|
||
|
||
iTrl = iDup = 0;
|
||
iKey = pPage->iCurKey;
|
||
iPos = iKey * iLen;
|
||
if ( iKey < pPage->iKeys )
|
||
{
|
||
iDup = pPage->pKeyBuf[ iPos + iNum + 4 ];
|
||
memmove( &pPage->pKeyBuf[ iPos + iLen ], &pPage->pKeyBuf[ iPos ],
|
||
iLen * ( pPage->iKeys - iKey ) );
|
||
}
|
||
if ( pKey->len >= iNum )
|
||
memcpy( &pPage->pKeyBuf[ iPos ], pKey->val, iNum );
|
||
else
|
||
{
|
||
memcpy( &pPage->pKeyBuf[ iPos ], pKey->val, pKey->len );
|
||
memset( &pPage->pKeyBuf[ iPos + pKey->len ], bTrail, iNum - pKey->len );
|
||
}
|
||
HB_PUT_LE_ULONG( &pPage->pKeyBuf[ iPos + iNum ], pKey->rec );
|
||
while ( iTrl < iNum && pPage->pKeyBuf[ iPos + iNum - iTrl - 1 ] == bTrail )
|
||
++iTrl;
|
||
if ( iKey > 0 )
|
||
{
|
||
iMax = iNum - HB_MAX( iTrl, pPage->pKeyBuf[ iPos - 1 ] );
|
||
if ( iDup > iMax )
|
||
{
|
||
iDup = iMax;
|
||
}
|
||
else
|
||
{
|
||
while ( iDup < iMax && pPage->pKeyBuf[ iPos + iDup ] ==
|
||
pPage->pKeyBuf[ iPos + iDup - iLen ] )
|
||
++iDup;
|
||
}
|
||
}
|
||
pPage->pKeyBuf[ iPos + iNum + 4 ] = (BYTE) iDup;
|
||
pPage->pKeyBuf[ iPos + iNum + 5 ] = (BYTE) iTrl;
|
||
iSpc = pPage->ReqByte + iNum - iTrl - iDup;
|
||
if ( iKey < pPage->iKeys )
|
||
{
|
||
iMax = iNum - HB_MAX( iTrl, pPage->pKeyBuf[ iPos + iLen + iLen - 1 ] );
|
||
iSpc += pPage->pKeyBuf[ iPos + iLen + iLen - 2 ];
|
||
iDup = 0;
|
||
while ( iDup < iMax && pPage->pKeyBuf[ iPos + iDup ] ==
|
||
pPage->pKeyBuf[ iPos + iDup + iLen ] )
|
||
++iDup;
|
||
iSpc -= ( pPage->pKeyBuf[ iPos + iLen + iLen - 2 ] = ( BYTE ) iDup );
|
||
}
|
||
pPage->iKeys++;
|
||
while ( pKey->rec > pPage->RNMask )
|
||
{
|
||
pPage->RNMask = ( pPage->RNMask << 8 ) | 0xFF;
|
||
pPage->ReqByte++;
|
||
pPage->RNBits += 8;
|
||
iSpc += pPage->iKeys;
|
||
}
|
||
pPage->iFree -= iSpc;
|
||
pPage->fBufChanged = pPage->fChanged = TRUE;
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxPageCheckKeys( pPage );
|
||
hb_cdxPageCheckDupTrl( pPage, pPage->pKeyBuf, pPage->iKeys );
|
||
#endif
|
||
if ( iKey >= pPage->iKeys - 1 )
|
||
iRet |= NODE_NEWLASTKEY;
|
||
if ( pPage->iFree < 0 )
|
||
iRet |= NODE_SPLIT;
|
||
if ( pPage->iFree >= pPage->ReqByte &&
|
||
pPage->Left != CDX_DUMMYNODE && pPage->Right != CDX_DUMMYNODE )
|
||
iRet |= NODE_BALANCE;
|
||
return iRet;
|
||
}
|
||
|
||
/*
|
||
* set (insert) key in interior node record to (with) given value
|
||
*/
|
||
static void hb_cdxPageIntSetKey( LPCDXPAGE pPage, SHORT iKey, BOOL fIns, BYTE * pbVal, ULONG ulRec, ULONG ulPag )
|
||
{
|
||
SHORT iLen = pPage->TagParent->uiLen;
|
||
SHORT iPos = iKey * ( iLen + 8 );
|
||
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf("\r\nintSetKey (%s): Page=%lx, iKey=%d/%d, ulPag=%lx",
|
||
fIns ? "ins" : "set", pPage->Page, iKey, pPage->iKeys, ulPag);
|
||
fflush(stdout);
|
||
#endif
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( ( pPage->PageType & CDX_NODE_LEAF ) != 0 )
|
||
hb_cdxErrInternal( "hb_cdxPageIntSetKey: page is a leaf!" );
|
||
if ( iKey < 0 || iKey >= pPage->iKeys + ( fIns ? 1 : 0 ) )
|
||
{
|
||
hb_cdxErrInternal( "hb_cdxPageIntSetKey: wrong iKey index." );
|
||
}
|
||
#endif
|
||
if ( fIns )
|
||
{
|
||
if ( iKey < pPage->iKeys )
|
||
{
|
||
memmove( &pPage->node.intNode.keyPool[ iPos + iLen + 8 ],
|
||
&pPage->node.intNode.keyPool[ iPos ],
|
||
( iLen + 8 ) * ( pPage->iKeys - iKey ) );
|
||
}
|
||
pPage->iKeys++;
|
||
}
|
||
if ( pbVal )
|
||
memcpy( &pPage->node.intNode.keyPool[ iPos ], pbVal, iLen );
|
||
else if ( fIns )
|
||
memset( &pPage->node.intNode.keyPool[ iPos ],
|
||
( pPage->TagParent->uiType == 'C' ) ? ' ' : '\0', iLen );
|
||
if ( ulRec )
|
||
HB_PUT_BE_ULONG( &pPage->node.intNode.keyPool[ iPos + iLen ], ulRec );
|
||
HB_PUT_BE_ULONG( &pPage->node.intNode.keyPool[ iPos + iLen + 4 ], ulPag );
|
||
pPage->fChanged = TRUE;
|
||
}
|
||
|
||
/*
|
||
* delete key in interior node record
|
||
*/
|
||
static void hb_cdxPageIntDelKey( LPCDXPAGE pPage, SHORT iKey )
|
||
{
|
||
SHORT iLen = pPage->TagParent->uiLen + 8;
|
||
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf("\r\nintDelKey: Page=%lx, iKey=%d/%d, ulPag=%lx",
|
||
pPage->Page, iKey, pPage->iKeys,
|
||
HB_GET_BE_ULONG( &pPage->node.intNode.keyPool[ (iKey+1) * iLen - 4 ] ) );
|
||
fflush(stdout);
|
||
#endif
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( ( pPage->PageType & CDX_NODE_LEAF ) != 0 )
|
||
hb_cdxErrInternal( "hb_cdxPageIntDelKey: page is a leaf!" );
|
||
if ( iKey < 0 || iKey >= pPage->iKeys )
|
||
{
|
||
hb_cdxErrInternal( "hb_cdxPageIntDelKey: wrong iKey index." );
|
||
}
|
||
#endif
|
||
pPage->iKeys--;
|
||
if ( pPage->iKeys > iKey )
|
||
{
|
||
memmove( &pPage->node.intNode.keyPool[ iKey * iLen ],
|
||
&pPage->node.intNode.keyPool[ ( iKey + 1 ) * iLen ], ( pPage->iKeys - iKey ) * iLen );
|
||
}
|
||
memset( &pPage->node.intNode.keyPool[ pPage->iKeys * iLen ], 0, iLen );
|
||
pPage->fChanged = TRUE;
|
||
}
|
||
|
||
/*
|
||
* (re)load CDX page from index file
|
||
*/
|
||
static void hb_cdxPageLoad( LPCDXPAGE pPage )
|
||
{
|
||
if ( pPage->pKeyBuf )
|
||
{
|
||
hb_xfree( pPage->pKeyBuf );
|
||
pPage->pKeyBuf = NULL;
|
||
pPage->fBufChanged = FALSE;
|
||
}
|
||
hb_cdxIndexPageRead( pPage->TagParent->pIndex, pPage->Page, (BYTE *) &pPage->node, sizeof( CDXNODE ) );
|
||
pPage->PageType = ( BYTE ) HB_GET_LE_USHORT( pPage->node.intNode.attr );
|
||
pPage->Left = HB_GET_LE_ULONG( pPage->node.intNode.leftPtr );
|
||
pPage->Right = HB_GET_LE_ULONG( pPage->node.intNode.rightPtr );
|
||
pPage->iKeys = HB_GET_LE_USHORT( pPage->node.intNode.nKeys );
|
||
pPage->fChanged = FALSE;
|
||
|
||
if ( ( pPage->PageType & CDX_NODE_LEAF ) != 0 )
|
||
{
|
||
pPage->iFree = HB_GET_LE_USHORT( pPage->node.extNode.freeSpc );
|
||
pPage->RNMask = HB_GET_LE_ULONG( pPage->node.extNode.recMask );
|
||
/* TODO: redundant, use it directly */
|
||
pPage->DCMask = pPage->node.extNode.dupMask;
|
||
pPage->TCMask = pPage->node.extNode.trlMask;
|
||
pPage->RNBits = pPage->node.extNode.recBits;
|
||
pPage->DCBits = pPage->node.extNode.dupBits;
|
||
pPage->TCBits = pPage->node.extNode.trlBits;
|
||
pPage->ReqByte = pPage->node.extNode.keyBytes;
|
||
pPage->bufKeyNum = 0;
|
||
#if 0
|
||
if ( !pPage->pKeyBuf )
|
||
{
|
||
BYTE *pKeyBuf = (BYTE *) hb_xgrab( ( pPage->iKeys + 1 ) * ( pPage->TagParent->uiLen + 6 ) );
|
||
hb_cdxPageLeafDecode( pPage, pKeyBuf );
|
||
pPage->pKeyBuf = pKeyBuf;
|
||
}
|
||
#endif
|
||
}
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxPageCheckKeys( pPage );
|
||
#endif
|
||
}
|
||
|
||
/*
|
||
* store page into index file
|
||
*/
|
||
static void hb_cdxPageStore( LPCDXPAGE pPage )
|
||
{
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( pPage->Page == 0 || pPage->Page == CDX_DUMMYNODE )
|
||
hb_cdxErrInternal( "hb_cdxPageStore: Page number wrong!." );
|
||
if ( pPage->PageType & CDX_NODE_LEAF )
|
||
{
|
||
if ( pPage->iFree < 0 )
|
||
hb_cdxErrInternal( "hb_cdxPageStore: FreeSpace calculated wrong!." );
|
||
}
|
||
else if ( pPage->iKeys > pPage->TagParent->MaxKeys )
|
||
hb_cdxErrInternal( "hb_cdxPageStore: number of keys exceed!." );
|
||
#endif
|
||
HB_PUT_LE_USHORT( pPage->node.intNode.attr, pPage->PageType );
|
||
HB_PUT_LE_USHORT( pPage->node.intNode.nKeys, pPage->iKeys );
|
||
HB_PUT_LE_ULONG( pPage->node.intNode.leftPtr, pPage->Left );
|
||
HB_PUT_LE_ULONG( pPage->node.intNode.rightPtr, pPage->Right );
|
||
|
||
if ( ( pPage->PageType & CDX_NODE_LEAF ) != 0 )
|
||
{
|
||
HB_PUT_LE_USHORT( pPage->node.extNode.freeSpc, pPage->iFree );
|
||
HB_PUT_LE_ULONG( pPage->node.extNode.recMask, pPage->RNMask );
|
||
/* TODO: redundant, use it directly */
|
||
pPage->node.extNode.dupMask = pPage->DCMask;
|
||
pPage->node.extNode.trlMask = pPage->TCMask;
|
||
pPage->node.extNode.recBits = pPage->RNBits;
|
||
pPage->node.extNode.dupBits = pPage->DCBits;
|
||
pPage->node.extNode.trlBits = pPage->TCBits;
|
||
pPage->node.extNode.keyBytes = pPage->ReqByte;
|
||
|
||
if ( pPage->pKeyBuf && pPage->fBufChanged )
|
||
{
|
||
hb_cdxPageLeafEncode( pPage, pPage->pKeyBuf, pPage->iKeys );
|
||
pPage->fBufChanged = FALSE;
|
||
}
|
||
//#if 0
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
if ( pPage->pKeyBuf )
|
||
{
|
||
hb_xfree( pPage->pKeyBuf );
|
||
pPage->pKeyBuf = NULL;
|
||
}
|
||
#endif
|
||
}
|
||
hb_cdxIndexPageWrite( pPage->TagParent->pIndex, pPage->Page, (BYTE *) &pPage->node, sizeof( CDXNODE ) );
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxPageCheckKeys( pPage );
|
||
#endif
|
||
pPage->fChanged = FALSE;
|
||
}
|
||
|
||
/*
|
||
* create new empty page and allocate space for it in index file if ulPage == 0
|
||
* or load it from index file if ulPage != CDX_DUMMYNODE
|
||
*/
|
||
static LPCDXPAGE hb_cdxPageNew( LPCDXTAG pTag, LPCDXPAGE pOwnerPage, ULONG ulPage )
|
||
{
|
||
LPCDXPAGE pPage = NULL;
|
||
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxTagPoolCheck( pTag );
|
||
#endif
|
||
if ( ulPage && ulPage != CDX_DUMMYNODE && pTag->pagePool )
|
||
{
|
||
pPage = pTag->pagePool;
|
||
while ( pPage && pPage->Page != ulPage )
|
||
{
|
||
pPage = pPage->pPoolNext;
|
||
}
|
||
}
|
||
if ( pPage )
|
||
{
|
||
if ( pPage->pPoolPrev )
|
||
{
|
||
pPage->pPoolPrev->pPoolNext = pPage->pPoolNext;
|
||
if ( pPage->pPoolNext )
|
||
{
|
||
pPage->pPoolNext->pPoolPrev = pPage->pPoolPrev;
|
||
}
|
||
pPage->pPoolPrev = NULL;
|
||
pPage->pPoolNext = pTag->pagePool;
|
||
pPage->pPoolNext->pPoolPrev = pPage;
|
||
pTag->pagePool = pPage;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pPage = ( LPCDXPAGE ) hb_xgrab( sizeof( CDXPAGE ) );
|
||
memset( pPage, 0, sizeof( CDXPAGE ) );
|
||
pPage->PageType = CDX_NODE_UNUSED;
|
||
pPage->Left = pPage->Right = CDX_DUMMYNODE;
|
||
pPage->TagParent = pTag;
|
||
|
||
if ( ulPage && ulPage != CDX_DUMMYNODE )
|
||
{
|
||
pPage->Page = ulPage;
|
||
hb_cdxPageLoad( pPage );
|
||
}
|
||
else if ( ! ulPage )
|
||
{
|
||
pPage->Page = hb_cdxIndexGetAvailPage( pTag->pIndex, FALSE );
|
||
pPage->fChanged = TRUE;
|
||
}
|
||
pPage->pPoolPrev = NULL;
|
||
pPage->pPoolNext = pTag->pagePool;
|
||
pTag->pagePool = pPage;
|
||
if ( pPage->pPoolNext )
|
||
pPage->pPoolNext->pPoolPrev = pPage;
|
||
}
|
||
pPage->Owner = pOwnerPage;
|
||
pPage->iCurKey = -1;
|
||
pPage->bUsed = 1;
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxTagPoolCheck( pTag );
|
||
#endif
|
||
return pPage;
|
||
}
|
||
|
||
/*
|
||
* free single page
|
||
*/
|
||
static void hb_cdxPageFree( LPCDXPAGE pPage, BOOL fReal )
|
||
{
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
LPCDXTAG pTag = pPage->TagParent;
|
||
hb_cdxTagPoolCheck( pTag );
|
||
#endif
|
||
if ( pPage->Child != NULL )
|
||
{
|
||
hb_cdxPageFree( pPage->Child, fReal );
|
||
pPage->Child = NULL;
|
||
}
|
||
|
||
if ( pPage->PageType == CDX_NODE_UNUSED )
|
||
{
|
||
fReal = TRUE;
|
||
pPage->fChanged = FALSE;
|
||
}
|
||
|
||
if ( fReal )
|
||
{
|
||
if ( pPage->fChanged )
|
||
hb_cdxPageStore( pPage );
|
||
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxTagPoolCheck( pTag );
|
||
#endif
|
||
if ( pPage->pPoolPrev )
|
||
{
|
||
pPage->pPoolPrev->pPoolNext = pPage->pPoolNext;
|
||
if ( pPage->pPoolNext )
|
||
{
|
||
pPage->pPoolNext->pPoolPrev = pPage->pPoolPrev;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pPage->TagParent->pagePool = pPage->pPoolNext;
|
||
if ( pPage->pPoolNext )
|
||
{
|
||
pPage->pPoolNext->pPoolPrev = NULL;
|
||
}
|
||
}
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxTagPoolCheck( pTag );
|
||
#endif
|
||
}
|
||
|
||
if ( pPage->Owner != NULL && pPage->Owner->Child == pPage )
|
||
pPage->Owner->Child = NULL;
|
||
pPage->Owner = NULL;
|
||
pPage->bUsed = 0;
|
||
|
||
if ( fReal )
|
||
{
|
||
if ( pPage->PageType == CDX_NODE_UNUSED )
|
||
hb_cdxIndexPutAvailPage( pPage->TagParent->pIndex, pPage->Page, FALSE );
|
||
if ( pPage->pKeyBuf )
|
||
hb_xfree( pPage->pKeyBuf );
|
||
hb_xfree( pPage );
|
||
}
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxTagPoolCheck( pTag );
|
||
#endif
|
||
}
|
||
|
||
/*
|
||
* read child page
|
||
*/
|
||
static void hb_cdxPageGetChild( LPCDXPAGE pPage )
|
||
{
|
||
ULONG ulPage;
|
||
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( ( pPage->PageType & CDX_NODE_LEAF ) != 0 )
|
||
hb_cdxErrInternal( "hb_cdxPageGetChild: index corrupted." );
|
||
#endif
|
||
|
||
ulPage = hb_cdxPageGetKeyPage( pPage, pPage->iCurKey );
|
||
if ( pPage->Child != NULL )
|
||
{
|
||
if ( pPage->Child->Page != ulPage )
|
||
{
|
||
hb_cdxPageFree( pPage->Child, FALSE );
|
||
pPage->Child = NULL;
|
||
}
|
||
}
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf("GetChild: Parent=%lx, Child=%lx\r\n", pPage->Page, ulPage); fflush(stdout);
|
||
#endif
|
||
if ( pPage->Child == NULL )
|
||
pPage->Child = hb_cdxPageNew( pPage->TagParent, pPage, ulPage );
|
||
}
|
||
|
||
static int hb_cdxPageKeyLeafBalance( LPCDXPAGE pPage, int iChildRet )
|
||
{
|
||
LPCDXPAGE childs[ CDX_BALANCE_LEAFPAGES + 2 ], lpTmpPage;
|
||
SHORT iChKeys[ CDX_BALANCE_LEAFPAGES + 2 ],
|
||
iChFree[ CDX_BALANCE_LEAFPAGES + 2 ];
|
||
SHORT iFirstKey, iBlncKeys = CDX_BALANCE_LEAFPAGES;
|
||
SHORT iLen = pPage->TagParent->uiLen + 6,
|
||
iKeys = 0, iFree = 0, iSkip = 0, iBufSize = 0;
|
||
BYTE * pKeyPool = NULL, * pPtr;
|
||
BOOL fIns;
|
||
ULONG ulPage;
|
||
int iRet = 0, i;
|
||
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxPageCheckKeys( pPage );
|
||
#endif
|
||
|
||
if ( pPage->iCurKey > 0 )
|
||
iFirstKey = pPage->iCurKey - 1;
|
||
else
|
||
{
|
||
iFirstKey = 0;
|
||
--iBlncKeys;
|
||
if ( pPage->Left != CDX_DUMMYNODE )
|
||
iRet |= NODE_BALANCE;
|
||
}
|
||
if ( iBlncKeys > pPage->iKeys - iFirstKey )
|
||
{
|
||
iBlncKeys = pPage->iKeys - iFirstKey;
|
||
if ( pPage->Right != CDX_DUMMYNODE )
|
||
iRet |= NODE_BALANCE;
|
||
}
|
||
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf("\r\nleaf balance: Page=%lx (%d/%d)", pPage->Page, iFirstKey, iBlncKeys);
|
||
fflush(stdout);
|
||
#endif
|
||
|
||
if ( ( iChildRet & ( NODE_SPLIT | NODE_JOIN ) ) == 0 &&
|
||
( iBlncKeys < 2 || ( iChildRet & NODE_BALANCE ) == 0 ) )
|
||
return iRet;
|
||
|
||
for ( i = 0; i < iBlncKeys; i++ )
|
||
{
|
||
ulPage = hb_cdxPageGetKeyPage( pPage, iFirstKey + i );
|
||
if ( pPage->Child && pPage->Child->Page == ulPage )
|
||
{
|
||
childs[i] = pPage->Child;
|
||
pPage->Child = NULL;
|
||
}
|
||
else
|
||
{
|
||
childs[i] = hb_cdxPageNew( pPage->TagParent, pPage, ulPage );
|
||
}
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( i > 0 && ( childs[i]->Page != childs[i-1]->Right ||
|
||
childs[i]->Left != childs[i-1]->Page ) )
|
||
{
|
||
printf("\r\nchilds[%d]->Page=%lx, childs[%d]->Right=%lx, childs[%d]->Page=%lx, childs[%d]->Left=%lx",
|
||
i-1, childs[i-1]->Page, i-1, childs[i-1]->Right,
|
||
i, childs[i]->Page, i, childs[i]->Left);
|
||
fflush(stdout);
|
||
hb_cdxErrInternal( "hb_cdxPageKeyLeafBalance: index corrupted." );
|
||
}
|
||
#endif
|
||
iChKeys[i] = childs[i]->iKeys;
|
||
iChFree[i] = childs[i]->iFree;
|
||
if ( childs[i]->iFree >= childs[i]->ReqByte ) /* TODO: increase limit for last page */
|
||
iFree += childs[i]->iFree;
|
||
else if ( childs[i]->iFree >= 0 )
|
||
{
|
||
if ( i == iSkip )
|
||
++iSkip;
|
||
#if 1
|
||
else if ( i + 1 == iBlncKeys && ( iChildRet & NODE_SPLIT ) == 0 )
|
||
{
|
||
iBlncKeys--;
|
||
hb_cdxPageFree( childs[i], FALSE );
|
||
}
|
||
#endif
|
||
}
|
||
if ( i >= iSkip && i < iBlncKeys )
|
||
iKeys += childs[i]->iKeys;
|
||
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf(", childs[%d]->Page=%lx(%d/%d)", i, childs[i]->Page, childs[i]->iKeys, childs[i]->iFree);
|
||
printf("(%d/%d/%d:%d,%lx)", i, iSkip, iBlncKeys, iKeys, childs[i]->Right);
|
||
fflush(stdout);
|
||
#endif
|
||
}
|
||
if ( ( iChildRet & NODE_SPLIT ) == 0 )
|
||
{
|
||
for ( i = iBlncKeys - 1; i > iSkip && childs[i]->iFree >= 0 && childs[i]->iFree < childs[i]->ReqByte; i-- )
|
||
{
|
||
iKeys -= childs[i]->iKeys;
|
||
hb_cdxPageFree( childs[i], FALSE );
|
||
iBlncKeys--;
|
||
}
|
||
}
|
||
if ( ( iChildRet & ( NODE_SPLIT | NODE_JOIN ) ) == 0 &&
|
||
( iBlncKeys < 2 || iFree < CDX_EXT_FREESPACE ) )
|
||
{
|
||
for ( i = 0; i < iBlncKeys; i++ )
|
||
hb_cdxPageFree( childs[i], FALSE );
|
||
return iRet;
|
||
}
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf("\r\nleaf balance: Page=%lx iKeys=%d", pPage->Page, iKeys);
|
||
fflush(stdout);
|
||
#endif
|
||
if ( iKeys > 0 )
|
||
{
|
||
iBufSize = iKeys;
|
||
pPtr = pKeyPool = (BYTE *) hb_xgrab( iBufSize * iLen );
|
||
for ( i = iSkip; i < iBlncKeys && iKeys > 0; i++ )
|
||
{
|
||
if ( childs[i]->iKeys > 0 )
|
||
{
|
||
if ( childs[i]->pKeyBuf )
|
||
memcpy( pPtr, childs[i]->pKeyBuf, childs[i]->iKeys * iLen );
|
||
else
|
||
hb_cdxPageLeafDecode( childs[i], pPtr );
|
||
/* update number of duplicate characters when join pages */
|
||
if ( pPtr > pKeyPool )
|
||
{
|
||
BYTE bDup = 0, bMax = iLen - 6 - HB_MAX( pPtr[ iLen - 1 ], pPtr[ -1 ] );
|
||
while ( bDup < bMax && pPtr[ bDup ] == pPtr[ bDup - iLen ] )
|
||
++bDup;
|
||
pPtr[ iLen - 2 ] = bDup;
|
||
if ( iSkip == i - 1 && childs[iSkip]->iFree >= 0 &&
|
||
iLen - 6 - bDup - pPtr[ iLen - 1 ] >
|
||
childs[iSkip]->iFree - childs[iSkip]->ReqByte )
|
||
{
|
||
memmove( pKeyPool, pPtr, childs[i]->iKeys * iLen );
|
||
pPtr = pKeyPool;
|
||
iKeys -= childs[i-1]->iKeys;
|
||
iSkip++;
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf("\r\niSkip=%d, iBlncKeys=%d", iSkip, iBlncKeys);
|
||
fflush(stdout);
|
||
#endif
|
||
}
|
||
}
|
||
pPtr += childs[i]->iKeys * iLen;
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf(", childs[%d]->iKeys=%d", i, childs[i]->iKeys);
|
||
fflush(stdout);
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxPageCheckDupTrl( pPage, pKeyPool, iKeys );
|
||
#endif
|
||
pPtr = pKeyPool;
|
||
fIns = FALSE;
|
||
i = iSkip;
|
||
while ( iKeys > 0 )
|
||
{
|
||
if ( i == iBlncKeys )
|
||
{
|
||
if ( childs[i-1]->Right != CDX_DUMMYNODE )
|
||
lpTmpPage = hb_cdxPageNew( pPage->TagParent, pPage, childs[i-1]->Right );
|
||
else
|
||
lpTmpPage = NULL;
|
||
|
||
if ( !fIns && lpTmpPage != NULL )
|
||
{
|
||
#if 1
|
||
SHORT j, iSize = 0, iMaxReq;
|
||
ULONG ulMaxRec = 0, ul;
|
||
BYTE * pbKey, bMax;
|
||
|
||
for ( j = 0; j < iKeys; j++ )
|
||
{
|
||
if ( ulMaxRec < ( ul = HB_GET_LE_ULONG( &pPtr[ ( j + 1 ) * iLen - 6 ] ) ) )
|
||
ulMaxRec = ul;
|
||
iSize += iLen - 6 - ( j == 0 ? 0 : pPtr[ ( j + 1 ) * iLen - 2 ] ) - pPtr[ ( j + 1 ) * iLen - 1 ];
|
||
}
|
||
pbKey = hb_cdxPageGetKeyVal( lpTmpPage, 0 );
|
||
bMax = ( lpTmpPage->node.extNode.keyPool[ lpTmpPage->ReqByte - 2 ]
|
||
>> ( 16 - lpTmpPage->TCBits ) ) & lpTmpPage->TCMask;
|
||
bMax = iLen - 6 - HB_MAX( pPtr[ iKeys * iLen - 1 ], bMax );
|
||
for ( j = 0; j < bMax &&
|
||
pPtr[ ( iKeys - 1 ) * iLen + j ] == pbKey[ j ]; j++ );
|
||
iSize -= j;
|
||
iMaxReq = lpTmpPage->ReqByte;
|
||
ul = lpTmpPage->RNMask;
|
||
while ( ulMaxRec > ul )
|
||
{
|
||
++iMaxReq;
|
||
ul = ( ul << 8 ) | 0xFF;
|
||
}
|
||
iSize += iKeys * iMaxReq;
|
||
iSize = lpTmpPage->iFree - iSize -
|
||
( iMaxReq - lpTmpPage->ReqByte ) * lpTmpPage->iKeys;
|
||
if ( iSize < 0 )
|
||
fIns = TRUE;
|
||
#else
|
||
if ( lpTmpPage->ReqByte > iMaxReq )
|
||
iMaxReq = lpTmpPage->ReqByte;
|
||
if ( lpTmpPage->iFree < iKeys * ( iLen - 6 + iMaxReq ) +
|
||
( iMaxReq - lpTmpPage->ReqByte ) * lpTmpPage->iKeys )
|
||
fIns = TRUE;
|
||
#endif
|
||
else
|
||
{
|
||
/* TODO: iBufSize to avoid new allocation if old buffer is large enough */
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf("\r\ninserting #keys=%d/%d (%d) parent=%lx, child=%lx, rec=%ld",
|
||
iKeys, lpTmpPage->iKeys, i, pPage->Page, lpTmpPage->Page, HB_GET_LE_ULONG( pPtr + iLen - 6 ));
|
||
fflush(stdout);
|
||
#endif
|
||
if ( iBufSize >= iKeys + lpTmpPage->iKeys )
|
||
{
|
||
memmove( pKeyPool, pPtr, iKeys * iLen );
|
||
}
|
||
else
|
||
{
|
||
BYTE * pTmp;
|
||
iBufSize = iKeys + lpTmpPage->iKeys;
|
||
pTmp = (BYTE *) hb_xgrab( iBufSize * iLen );
|
||
memcpy( pTmp, pPtr, iKeys * iLen );
|
||
hb_xfree( pKeyPool );
|
||
pKeyPool = pTmp;
|
||
}
|
||
if ( lpTmpPage->iKeys > 0 )
|
||
{
|
||
BYTE bDup = 0, bMax;
|
||
pPtr = &pKeyPool[ iKeys * iLen ];
|
||
if ( lpTmpPage->pKeyBuf )
|
||
memcpy( pPtr, lpTmpPage->pKeyBuf, lpTmpPage->iKeys * iLen );
|
||
else
|
||
hb_cdxPageLeafDecode( lpTmpPage, pPtr );
|
||
bMax = iLen - 6 - HB_MAX( pPtr[ iLen - 1 ], pPtr[ -1 ] );
|
||
while ( bDup < bMax && pPtr[ bDup ] == pPtr[ bDup - iLen ] )
|
||
++bDup;
|
||
pPtr[ iLen - 2 ] = bDup;
|
||
iKeys += lpTmpPage->iKeys;
|
||
}
|
||
pPtr = pKeyPool;
|
||
childs[i] = lpTmpPage;
|
||
if ( iFirstKey + i >= pPage->iKeys )
|
||
iRet |= NODE_NEWLASTKEY;
|
||
#if 0
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
childs[i]->iKeys = 0;
|
||
if ( childs[i]->pKeyBuf )
|
||
{
|
||
hb_xfree( childs[i]->pKeyBuf );
|
||
childs[i]->pKeyBuf = NULL;
|
||
childs[i]->fBufChanged = FALSE;
|
||
}
|
||
hb_cdxPageCalcLeafSpace( childs[i], pPtr, iKeys );
|
||
hb_cdxPageLeafEncode( childs[i], pPtr, childs[i]->iKeys );
|
||
if ( iSize != childs[i]->iFree )
|
||
{
|
||
printf("\r\ninserting, iSize=%d, childs[i]->iFree=%d", iSize, childs[i]->iFree); fflush(stdout);
|
||
printf("\r\niKeys=%d, iMaxReq=%d", iKeys, iMaxReq); fflush(stdout);
|
||
hb_cdxErrInternal( "hb_cdxPageGetChild: index corrupted." );
|
||
}
|
||
#endif
|
||
#endif
|
||
}
|
||
}
|
||
else
|
||
fIns = TRUE;
|
||
|
||
if ( fIns )
|
||
{
|
||
childs[ i ] = hb_cdxPageNew( pPage->TagParent, pPage, 0 );
|
||
childs[ i ]->PageType = CDX_NODE_LEAF;
|
||
/* Update siblings links */
|
||
childs[ i ]->Left = childs[i-1]->Page;
|
||
childs[ i ]->Right = childs[i-1]->Right;
|
||
childs[i-1]->Right = childs[ i ]->Page;
|
||
childs[i-1]->fChanged = TRUE;
|
||
if ( lpTmpPage != NULL )
|
||
{
|
||
lpTmpPage->Left = childs[i]->Page;
|
||
lpTmpPage->fChanged = TRUE;
|
||
hb_cdxPageFree( lpTmpPage, FALSE );
|
||
}
|
||
iBlncKeys++;
|
||
iRet |= NODE_BALANCE;
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf("\r\nleaf balance: new child[%d]->Page=%lx",i,childs[i]->Page);
|
||
fflush(stdout);
|
||
#endif
|
||
}
|
||
}
|
||
childs[i]->iKeys = 0;
|
||
if ( childs[i]->pKeyBuf )
|
||
{
|
||
hb_xfree( childs[i]->pKeyBuf );
|
||
childs[i]->pKeyBuf = NULL;
|
||
childs[i]->fBufChanged = FALSE;
|
||
}
|
||
hb_cdxPageCalcLeafSpace( childs[i], pPtr, iKeys );
|
||
if ( i == iSkip && i < iBlncKeys && !childs[i]->fChanged &&
|
||
childs[i]->iKeys == iChKeys[i] &&
|
||
childs[i]->iFree == iChFree[i] )
|
||
{
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf("\r\niskip++\r\n");fflush(stdout);
|
||
#endif
|
||
iSkip++;
|
||
}
|
||
else
|
||
{
|
||
hb_cdxPageLeafEncode( childs[i], pPtr, childs[i]->iKeys );
|
||
}
|
||
pPtr += childs[i]->iKeys * iLen;
|
||
iKeys -= childs[i]->iKeys;
|
||
/* update parent key */
|
||
if ( i < iBlncKeys )
|
||
hb_cdxPageIntSetKey( pPage, iFirstKey + i, fIns,
|
||
pPtr - iLen, HB_GET_LE_ULONG( pPtr - 6 ),
|
||
childs[i]->Page );
|
||
else
|
||
iBlncKeys++;
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf(" (%d/%d)", childs[i]->iKeys,childs[i]->iFree);
|
||
fflush(stdout);
|
||
#endif
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxPageCheckKeys( childs[i] );
|
||
#endif
|
||
i++;
|
||
}
|
||
if ( i < iBlncKeys )
|
||
{
|
||
/* Update siblings links */
|
||
#if 1
|
||
if ( childs[iBlncKeys-1]->Right != CDX_DUMMYNODE &&
|
||
( i > 1 || ( i == 1 && childs[0]->Left == CDX_DUMMYNODE ) ) )
|
||
{
|
||
ULONG Page;
|
||
Page = childs[iBlncKeys-1]->Page;
|
||
childs[iBlncKeys-1]->Page = childs[i-1]->Page;
|
||
childs[i-1]->Page = Page;
|
||
hb_cdxPageIntSetKey( pPage, iFirstKey + i - 1, FALSE, NULL, 0, Page );
|
||
childs[i-1]->Right = childs[iBlncKeys-1]->Right;
|
||
childs[i-1]->fChanged = TRUE;
|
||
if ( i > 1 )
|
||
{
|
||
childs[i-2]->Right = Page;
|
||
childs[i-2]->fChanged = TRUE;
|
||
}
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
ULONG Left, Right;
|
||
Right = childs[iBlncKeys-1]->Right;
|
||
if ( i > 0 )
|
||
{
|
||
Left = childs[i-1]->Page;
|
||
childs[i-1]->Right = Right;
|
||
childs[i-1]->fChanged = TRUE;
|
||
}
|
||
else
|
||
{
|
||
Left = childs[0]->Left;
|
||
if ( Left != CDX_DUMMYNODE )
|
||
{
|
||
lpTmpPage = hb_cdxPageNew( pPage->TagParent, pPage, Left );
|
||
lpTmpPage->Right = Right;
|
||
lpTmpPage->fChanged = TRUE;
|
||
hb_cdxPageFree( lpTmpPage, FALSE );
|
||
}
|
||
}
|
||
if ( Right != CDX_DUMMYNODE )
|
||
{
|
||
lpTmpPage = hb_cdxPageNew( pPage->TagParent, pPage, Right );
|
||
lpTmpPage->Left = Left;
|
||
lpTmpPage->fChanged = TRUE;
|
||
hb_cdxPageFree( lpTmpPage, FALSE );
|
||
}
|
||
}
|
||
/* Unlink empty pages from parent */
|
||
while ( i < iBlncKeys )
|
||
{
|
||
/* Delete parent key */
|
||
iBlncKeys--;
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf("\r\nleaf balance: free child[%d]->Page=%lx", iBlncKeys, childs[iBlncKeys]->Page);
|
||
fflush(stdout);
|
||
#endif
|
||
if ( childs[iBlncKeys]->pKeyBuf )
|
||
{
|
||
hb_xfree( childs[iBlncKeys ]->pKeyBuf );
|
||
childs[iBlncKeys]->pKeyBuf = NULL;
|
||
childs[iBlncKeys]->fBufChanged = FALSE;
|
||
}
|
||
hb_cdxPageIntDelKey( pPage, iFirstKey + iBlncKeys );
|
||
childs[iBlncKeys]->Owner = NULL;
|
||
childs[iBlncKeys]->fChanged = FALSE;
|
||
childs[iBlncKeys]->PageType = CDX_NODE_UNUSED;
|
||
childs[iBlncKeys]->Left = CDX_DUMMYNODE;
|
||
childs[iBlncKeys]->Right = CDX_DUMMYNODE;
|
||
hb_cdxPageFree( childs[iBlncKeys], FALSE );
|
||
}
|
||
iRet |= NODE_BALANCE;
|
||
}
|
||
for ( i = 0; i < iBlncKeys; i++ )
|
||
hb_cdxPageFree( childs[i], FALSE );
|
||
|
||
if ( pKeyPool )
|
||
hb_xfree( pKeyPool );
|
||
pPage->fChanged = TRUE;
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxPageCheckKeys( pPage );
|
||
#endif
|
||
if ( pPage->iKeys > pPage->TagParent->MaxKeys )
|
||
iRet |= NODE_SPLIT;
|
||
return iRet;
|
||
}
|
||
|
||
static int hb_cdxPageKeyIntBalance( LPCDXPAGE pPage, int iChildRet )
|
||
{
|
||
LPCDXPAGE childs[ CDX_BALANCE_INTPAGES + 2 ], lpTmpPage;
|
||
SHORT iFirstKey, iBlncKeys = CDX_BALANCE_INTPAGES;
|
||
SHORT iLen = pPage->TagParent->uiLen + 8, iKeys = 0, iNeedKeys, iNodeKeys,
|
||
iMin = pPage->TagParent->MaxKeys, iMax = 0, iDiv;
|
||
ULONG ulPage;
|
||
BYTE * pKeyPool = NULL, *pPtr;
|
||
BOOL fForce = ( iChildRet & ( NODE_SPLIT | NODE_JOIN ) ) != 0;
|
||
int iRet = 0, i;
|
||
|
||
if ( !fForce && ( iChildRet & NODE_BALANCE ) == 0 )
|
||
return iRet;
|
||
|
||
if ( pPage->Child && pPage->Child->Child )
|
||
hb_cdxPageFree( pPage->Child->Child, FALSE );
|
||
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxPageCheckKeys( pPage );
|
||
#endif
|
||
|
||
if ( pPage->iKeys <= iBlncKeys || pPage->iCurKey <= iBlncKeys / 2 )
|
||
iFirstKey = 0;
|
||
else if ( pPage->iCurKey + ( iBlncKeys >> 1 ) >= pPage->iKeys )
|
||
iFirstKey = pPage->iKeys - iBlncKeys;
|
||
else
|
||
iFirstKey = pPage->iCurKey - ( iBlncKeys >> 1 );
|
||
if ( iBlncKeys > pPage->iKeys - iFirstKey )
|
||
{
|
||
iBlncKeys = pPage->iKeys - iFirstKey;
|
||
iRet |= NODE_BALANCE;
|
||
}
|
||
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf("\r\nbalance: Page=%lx (%d/%d)", pPage->Page, iFirstKey, iBlncKeys);
|
||
fflush(stdout);
|
||
#endif
|
||
|
||
if ( !fForce && iBlncKeys < 2 )
|
||
return iRet;
|
||
|
||
for ( i = 0; i < iBlncKeys; i++ )
|
||
{
|
||
ulPage = hb_cdxPageGetKeyPage( pPage, iFirstKey + i );
|
||
if ( pPage->Child && pPage->Child->Page == ulPage )
|
||
{
|
||
childs[i] = pPage->Child;
|
||
pPage->Child = NULL;
|
||
}
|
||
else
|
||
{
|
||
childs[i] = hb_cdxPageNew( pPage->TagParent, pPage, ulPage );
|
||
}
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( i > 0 && ( childs[i]->Page != childs[i-1]->Right ||
|
||
childs[i]->Left != childs[i-1]->Page ) )
|
||
{
|
||
printf("\r\nchilds[%d]->Page=%lx, childs[%d]->Right=%lx, childs[%d]->Page=%lx, childs[%d]->Left=%lx",
|
||
i-1, childs[i-1]->Page, i-1, childs[i-1]->Right,
|
||
i, childs[i]->Page, i, childs[i]->Left);
|
||
fflush(stdout);
|
||
hb_cdxErrInternal( "hb_cdxPageKeyIntBalance: index corrupted." );
|
||
}
|
||
#endif
|
||
iKeys += childs[i]->iKeys;
|
||
|
||
if ( childs[i]->iKeys > iMax )
|
||
iMax = childs[i]->iKeys;
|
||
if ( childs[i]->iKeys < iMin )
|
||
iMin = childs[i]->iKeys;
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf(", childs[%d]->Page=%lx(%d)", i, childs[i]->Page, childs[i]->iKeys);
|
||
fflush(stdout);
|
||
#endif
|
||
}
|
||
iNeedKeys = ( iKeys + pPage->TagParent->MaxKeys - 1 )
|
||
/ pPage->TagParent->MaxKeys;
|
||
#if 1
|
||
if ( iNeedKeys == 1 && iBlncKeys > 1 && childs[0]->Left != CDX_DUMMYNODE &&
|
||
childs[iBlncKeys-1]->Right != CDX_DUMMYNODE &&
|
||
iKeys >= CDX_BALANCE_INTPAGES << 1 &&
|
||
iKeys > pPage->TagParent->MaxKeys * 3 >> 1 )
|
||
{
|
||
iNeedKeys = 2;
|
||
}
|
||
#endif
|
||
#if 1
|
||
iDiv = HB_MAX( iMax - iMin - ( pPage->TagParent->MaxKeys >> 1 ) + 1,
|
||
iBlncKeys - iNeedKeys );
|
||
#else
|
||
iDiv = iMax - iMin;
|
||
#endif
|
||
if ( iDiv >= 2 || fForce )
|
||
{
|
||
#if 1
|
||
if ( iBlncKeys == 1 && iKeys > pPage->TagParent->MaxKeys &&
|
||
childs[0]->Right != CDX_DUMMYNODE )
|
||
{
|
||
lpTmpPage = hb_cdxPageNew( pPage->TagParent, pPage, childs[0]->Right );
|
||
iKeys += lpTmpPage->iKeys;
|
||
childs[iBlncKeys++] = lpTmpPage;
|
||
if ( iFirstKey + iBlncKeys > pPage->iKeys )
|
||
iRet |= NODE_NEWLASTKEY;
|
||
iNeedKeys = ( iKeys + pPage->TagParent->MaxKeys - 1 )
|
||
/ pPage->TagParent->MaxKeys;
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
iMax = ( iKeys + iNeedKeys - 1 ) / iNeedKeys;
|
||
iMin = HB_MAX( iKeys / iNeedKeys, 1 );
|
||
for ( i = iBlncKeys - 1; i > 1 &&
|
||
childs[i]->iKeys >= iMin && childs[i]->iKeys <= iMax; i-- )
|
||
{
|
||
iKeys -= childs[i]->iKeys;
|
||
hb_cdxPageFree( childs[i], FALSE );
|
||
iBlncKeys--;
|
||
iMax = ( iKeys + iNeedKeys - 1 ) / iNeedKeys;
|
||
iMin = HB_MAX( iKeys / iNeedKeys, 1 );
|
||
}
|
||
while ( iBlncKeys > 2 && childs[0]->iKeys >= iMin && childs[0]->iKeys <= iMax )
|
||
{
|
||
iKeys -= childs[0]->iKeys;
|
||
hb_cdxPageFree( childs[0], FALSE );
|
||
iBlncKeys--;
|
||
iFirstKey++;
|
||
for ( i = 0; i < iBlncKeys; i++ )
|
||
{
|
||
childs[i] = childs[i+1];
|
||
}
|
||
iMax = ( iKeys + iNeedKeys - 1 ) / iNeedKeys;
|
||
iMin = HB_MAX( iKeys / iNeedKeys, 1 );
|
||
}
|
||
}
|
||
}
|
||
if ( !fForce && ( iBlncKeys < 2 || iDiv < 2 ) )
|
||
{
|
||
for ( i = 0; i < iBlncKeys; i++ )
|
||
hb_cdxPageFree( childs[i], FALSE );
|
||
return iRet;
|
||
}
|
||
|
||
if ( iKeys > 0 )
|
||
{
|
||
pPtr = pKeyPool = (BYTE*) hb_xgrab( iKeys * iLen );
|
||
for ( i = 0; i < iBlncKeys; i++ )
|
||
{
|
||
if ( childs[i]->iKeys > 0 )
|
||
{
|
||
memcpy( pPtr, childs[i]->node.intNode.keyPool, childs[i]->iKeys * iLen );
|
||
pPtr += childs[i]->iKeys * iLen;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( iNeedKeys > iBlncKeys )
|
||
{
|
||
if ( iBlncKeys < 2 )
|
||
i = iBlncKeys;
|
||
else
|
||
{
|
||
i = iBlncKeys - 1;
|
||
childs[iBlncKeys] = childs[i];
|
||
}
|
||
childs[ i ] = hb_cdxPageNew( pPage->TagParent, pPage, 0 );
|
||
childs[ i ]->PageType = CDX_NODE_BRANCH;
|
||
childs[ i ]->iKeys = 0;
|
||
childs[ i ]->fChanged = TRUE;
|
||
/* Add new parent key */
|
||
hb_cdxPageIntSetKey( pPage, iFirstKey + i, TRUE,
|
||
NULL, 0, childs[iBlncKeys]->Page );
|
||
/* Update siblings links */
|
||
childs[ i ]->Left = childs[i-1]->Page;
|
||
childs[ i ]->Right = childs[i-1]->Right;
|
||
childs[i-1]->Right = childs[ i ]->Page;
|
||
if ( i < iBlncKeys )
|
||
childs[i+1]->Left = childs[i]->Page;
|
||
else if ( childs[i]->Right != CDX_DUMMYNODE )
|
||
{
|
||
lpTmpPage = hb_cdxPageNew( pPage->TagParent, pPage, childs[iBlncKeys]->Right );
|
||
lpTmpPage->Left = childs[i]->Page;
|
||
lpTmpPage->fChanged = TRUE;
|
||
hb_cdxPageFree( lpTmpPage, FALSE );
|
||
}
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf("\r\nint balance: new child[%d]->Page=%lx",iBlncKeys,childs[iBlncKeys]->Page);
|
||
fflush(stdout);
|
||
#endif
|
||
iBlncKeys++;
|
||
iRet |= NODE_BALANCE;
|
||
}
|
||
else if ( iNeedKeys < iBlncKeys )
|
||
{
|
||
ULONG Left, Right;
|
||
|
||
/* Update siblings links */
|
||
if ( iNeedKeys > 1 )
|
||
{
|
||
childs[iNeedKeys-2]->Right = childs[iBlncKeys-1]->Page;
|
||
childs[iBlncKeys-1]->Left = childs[iNeedKeys-2]->Page;
|
||
lpTmpPage = childs[iBlncKeys-1];
|
||
childs[iBlncKeys-1] = childs[iNeedKeys-1];
|
||
childs[iNeedKeys-1] = lpTmpPage;
|
||
}
|
||
else if ( iNeedKeys > 0 && childs[0]->Left == CDX_DUMMYNODE )
|
||
{
|
||
lpTmpPage = childs[iBlncKeys-1];
|
||
childs[iBlncKeys-1] = childs[0];
|
||
childs[0] = lpTmpPage;
|
||
childs[0]->Left = CDX_DUMMYNODE;
|
||
}
|
||
else
|
||
{
|
||
Right = childs[iBlncKeys-1]->Right;
|
||
if ( iNeedKeys > 0 )
|
||
{
|
||
Left = childs[iNeedKeys-1]->Page;
|
||
childs[iNeedKeys-1]->Right = Right;
|
||
}
|
||
else
|
||
{
|
||
Left = childs[0]->Left;
|
||
if ( Left != CDX_DUMMYNODE )
|
||
{
|
||
lpTmpPage = hb_cdxPageNew( pPage->TagParent, pPage, Left );
|
||
lpTmpPage->Right = Right;
|
||
lpTmpPage->fChanged = TRUE;
|
||
hb_cdxPageFree( lpTmpPage, FALSE );
|
||
}
|
||
}
|
||
if ( Right != CDX_DUMMYNODE )
|
||
{
|
||
lpTmpPage = hb_cdxPageNew( pPage->TagParent, pPage, Right );
|
||
lpTmpPage->Left = Left;
|
||
lpTmpPage->fChanged = TRUE;
|
||
hb_cdxPageFree( lpTmpPage, FALSE );
|
||
}
|
||
}
|
||
/* Unlink empty pages from parent */
|
||
for ( i = iBlncKeys - 1; i >= iNeedKeys; i-- )
|
||
{
|
||
/* Delete parent key */
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf("\r\nbalance: free child[%d]->Page=%lx",i,childs[i]->Page);
|
||
fflush(stdout);
|
||
#endif
|
||
hb_cdxPageIntDelKey( pPage, iFirstKey + i );
|
||
childs[i]->Owner = NULL;
|
||
childs[i]->fChanged = FALSE;
|
||
childs[i]->PageType = CDX_NODE_UNUSED;
|
||
childs[i]->Left = CDX_DUMMYNODE;
|
||
childs[i]->Right = CDX_DUMMYNODE;
|
||
childs[i]->iKeys = 0;
|
||
hb_cdxPageFree( childs[i], FALSE );
|
||
}
|
||
iBlncKeys = iNeedKeys;
|
||
iRet |= NODE_BALANCE;
|
||
}
|
||
|
||
/*
|
||
* Redistribute childs internal node's keys and update parent keys
|
||
*/
|
||
if ( iKeys > 0 )
|
||
{
|
||
pPtr = pKeyPool;
|
||
for ( i = 0; i < iBlncKeys; i++ )
|
||
{
|
||
iNodeKeys = ( iKeys + iBlncKeys - i - 1 ) / ( iBlncKeys - i );
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( iNodeKeys > pPage->TagParent->MaxKeys )
|
||
hb_cdxErrInternal( "hb_cdxPageKeyIntBalance: iNodeKeys calculated wrong!." );
|
||
#endif
|
||
/* TODO: do nothing if iNodeKeys == childs[i]->iKeys && i == iSkip */
|
||
memcpy( childs[i]->node.intNode.keyPool, pPtr, iNodeKeys * iLen );
|
||
childs[i]->iKeys = iNodeKeys;
|
||
childs[i]->fChanged = TRUE;
|
||
pPtr += iNodeKeys * iLen;
|
||
iKeys -= iNodeKeys;
|
||
/* update parent key */
|
||
if ( iFirstKey + i < pPage->iKeys )
|
||
{
|
||
hb_cdxPageIntSetKey( pPage, iFirstKey + i, FALSE,
|
||
pPtr - iLen, HB_GET_BE_ULONG( pPtr - 8 ),
|
||
childs[i]->Page );
|
||
}
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
printf(" (%d)", childs[i]->iKeys);
|
||
#endif
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxPageCheckKeys( childs[i] );
|
||
#endif
|
||
hb_cdxPageFree( childs[i], FALSE );
|
||
}
|
||
hb_xfree( pKeyPool );
|
||
}
|
||
pPage->fChanged = TRUE;
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxPageCheckKeys( pPage );
|
||
#endif
|
||
if ( pPage->iKeys > pPage->TagParent->MaxKeys )
|
||
iRet |= NODE_SPLIT;
|
||
return iRet;
|
||
}
|
||
|
||
/*
|
||
* balance keys in child pages
|
||
*/
|
||
static int hb_cdxPageBalance( LPCDXPAGE pPage, int iChildRet )
|
||
{
|
||
int iRet = 0;
|
||
|
||
if ( ( pPage->PageType & CDX_NODE_LEAF ) != 0 )
|
||
iRet = iChildRet;
|
||
else
|
||
{
|
||
if ( iChildRet & NODE_NEWLASTKEY )
|
||
{
|
||
if ( pPage->Child->iKeys == 0 )
|
||
{
|
||
iChildRet |= NODE_JOIN;
|
||
iRet |= NODE_NEWLASTKEY;
|
||
}
|
||
else
|
||
{
|
||
hb_cdxPageIntSetKey( pPage, pPage->iCurKey, FALSE,
|
||
hb_cdxPageGetKeyVal( pPage->Child, pPage->Child->iKeys-1 ),
|
||
hb_cdxPageGetKeyRec( pPage->Child, pPage->Child->iKeys-1 ),
|
||
pPage->Child->Page );
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxPageCheckKeys( pPage );
|
||
#endif
|
||
pPage->fChanged = TRUE;
|
||
if ( pPage->iCurKey >= pPage->iKeys - 1 )
|
||
iRet |= NODE_NEWLASTKEY;
|
||
}
|
||
}
|
||
if ( ( pPage->Child->PageType & CDX_NODE_LEAF ) != 0 )
|
||
iRet |= hb_cdxPageKeyLeafBalance( pPage, iChildRet );
|
||
else
|
||
iRet |= hb_cdxPageKeyIntBalance( pPage, iChildRet );
|
||
}
|
||
if ( !pPage->Owner )
|
||
{
|
||
if ( pPage->iKeys == 0 )
|
||
{
|
||
pPage->PageType |= CDX_NODE_LEAF;
|
||
hb_cdxPageLeafInitSpace( pPage );
|
||
}
|
||
else if ( iRet & NODE_SPLIT )
|
||
iRet = hb_cdxPageRootSplit( pPage );
|
||
}
|
||
return iRet;
|
||
}
|
||
|
||
/*
|
||
* split Root Page
|
||
*/
|
||
static int hb_cdxPageRootSplit( LPCDXPAGE pPage )
|
||
{
|
||
LPCDXPAGE pNewRoot;
|
||
ULONG ulPage;
|
||
|
||
pNewRoot = hb_cdxPageNew( pPage->TagParent, NULL, 0 );
|
||
/*
|
||
* do not change root page address if it's unnecessary
|
||
* so we don't have to update Tag header
|
||
*/
|
||
pPage->TagParent->RootPage = pNewRoot;
|
||
ulPage = pNewRoot->Page;
|
||
pNewRoot->Page = pPage->Page;
|
||
pPage->Page = ulPage;
|
||
|
||
pPage->Owner = pNewRoot;
|
||
pPage->PageType &= ~CDX_NODE_ROOT;
|
||
pNewRoot->PageType = CDX_NODE_ROOT | CDX_NODE_BRANCH;
|
||
pNewRoot->fChanged = TRUE;
|
||
pNewRoot->Child = pPage;
|
||
pNewRoot->iCurKey = 0;
|
||
hb_cdxPageIntSetKey( pNewRoot, 0, TRUE,
|
||
hb_cdxPageGetKeyVal( pPage, pPage->iKeys-1 ),
|
||
hb_cdxPageGetKeyRec( pPage, pPage->iKeys-1 ),
|
||
pPage->Page );
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxPageCheckKeys( pNewRoot );
|
||
hb_cdxTagPoolCheck( pPage->TagParent );
|
||
#endif
|
||
hb_cdxPageBalance( pNewRoot, NODE_SPLIT );
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* remove current Key from Tag
|
||
*/
|
||
static int hb_cdxPageKeyDelete( LPCDXPAGE pPage )
|
||
{
|
||
int iChildRet;
|
||
|
||
if ( pPage->PageType & CDX_NODE_LEAF )
|
||
iChildRet = hb_cdxPageLeafDelKey( pPage );
|
||
else /* interior node */
|
||
iChildRet = hb_cdxPageKeyDelete( pPage->Child );
|
||
return hb_cdxPageBalance( pPage, iChildRet );
|
||
}
|
||
|
||
/*
|
||
* add Key to Tag at current position
|
||
*/
|
||
static int hb_cdxPageKeyInsert( LPCDXPAGE pPage, LPCDXKEY pKey )
|
||
{
|
||
int iChildRet;
|
||
|
||
if ( pPage->PageType & CDX_NODE_LEAF )
|
||
iChildRet = hb_cdxPageLeafAddKey( pPage, pKey );
|
||
else /* interior node */
|
||
iChildRet = hb_cdxPageKeyInsert( pPage->Child, pKey );
|
||
#ifdef HB_CDX_DBGUPDT
|
||
cdxTmpStackSize++;
|
||
#endif
|
||
return hb_cdxPageBalance( pPage, iChildRet );
|
||
}
|
||
|
||
/*
|
||
* Store Tag header to index files
|
||
*/
|
||
static void hb_cdxTagHeaderStore( LPCDXTAG pTag )
|
||
{
|
||
USHORT uiKeyLen, uiForLen;
|
||
CDXTAGHEADER tagHeader;
|
||
|
||
if ( !pTag->TagChanged )
|
||
return;
|
||
|
||
/*
|
||
* TODO: !!! read the following field from the index file,
|
||
* at least freePtr has to be read for pTag->TagBlock == 0
|
||
* tagHeader.freePtr [ 4 ] offset of list of free pages or -1
|
||
* tagHeader.reserved1[ 4 ] Version number ???
|
||
* tagHeader.reserved2[ 486 ]
|
||
*/
|
||
|
||
pTag->TagChanged = FALSE;
|
||
if ( pTag->UniqueKey )
|
||
pTag->OptFlags |= CDX_TYPE_UNIQUE;
|
||
if ( pTag->Temporary )
|
||
pTag->OptFlags |= CDX_TYPE_TEMPORARY;
|
||
if ( pTag->Custom )
|
||
pTag->OptFlags |= CDX_TYPE_CUSTOM;
|
||
if ( pTag->pForItem != NULL )
|
||
pTag->OptFlags |= CDX_TYPE_FORFILTER;
|
||
|
||
memset( &tagHeader, 0, sizeof( CDXTAGHEADER ) );
|
||
HB_PUT_LE_ULONG( tagHeader.rootPtr, pTag->RootBlock );
|
||
HB_PUT_LE_USHORT( tagHeader.keySize, pTag->uiLen );
|
||
tagHeader.indexOpt = pTag->OptFlags;
|
||
tagHeader.indexSig = 1;
|
||
if ( !pTag->AscendKey )
|
||
HB_PUT_LE_USHORT( tagHeader.ascendFlg, 1 );
|
||
|
||
uiKeyLen = pTag->KeyExpr == NULL ? 0 : strlen( pTag->KeyExpr );
|
||
uiForLen = pTag->ForExpr == NULL ? 0 : strlen( pTag->ForExpr );
|
||
|
||
HB_PUT_LE_USHORT( tagHeader.keyExpPos, 0 );
|
||
HB_PUT_LE_USHORT( tagHeader.keyExpLen, uiKeyLen + 1 );
|
||
HB_PUT_LE_USHORT( tagHeader.forExpPos, uiKeyLen + 1 );
|
||
HB_PUT_LE_USHORT( tagHeader.forExpLen, uiForLen + 1 );
|
||
if ( uiKeyLen > 0 )
|
||
{
|
||
strcpy( ( char * ) tagHeader.keyExpPool, pTag->KeyExpr );
|
||
}
|
||
if ( uiForLen > 0 )
|
||
{
|
||
strcpy( ( char * ) tagHeader.keyExpPool + uiKeyLen + 1, pTag->ForExpr );
|
||
}
|
||
hb_cdxIndexPageWrite( pTag->pIndex, pTag->TagBlock, (BYTE *) &tagHeader, sizeof( CDXTAGHEADER ) );
|
||
}
|
||
|
||
/*
|
||
* Read a tag definition from the index file
|
||
*/
|
||
static void hb_cdxTagLoad( LPCDXTAG pTag )
|
||
{
|
||
CDXTAGHEADER pHeader;
|
||
HB_MACRO_PTR pMacro;
|
||
ULONG ulRecNo;
|
||
|
||
/* read the page from a file */
|
||
hb_cdxIndexPageRead( pTag->pIndex, pTag->TagBlock, (BYTE *) &pHeader, sizeof( CDXTAGHEADER ) );
|
||
pTag->RootBlock = HB_GET_LE_ULONG( pHeader.rootPtr );
|
||
/* Return if:
|
||
* no root page allocated
|
||
* invalid root page offset (position inside an index file)
|
||
* invalid key value length
|
||
*/
|
||
if ( pTag->RootBlock == 0 || pTag->RootBlock % CDX_PAGELEN != 0 ||
|
||
pTag->RootBlock >= hb_fsSeek( pTag->pIndex->hFile, 0, FS_END ) ||
|
||
HB_GET_LE_USHORT( pHeader.keySize ) > CDX_MAXKEY )
|
||
{
|
||
/* TODO: pTag->RootBlock = 0; || {internal,RT}Error ? */
|
||
return;
|
||
}
|
||
pTag->uiLen = HB_GET_LE_USHORT( pHeader.keySize );
|
||
pTag->MaxKeys = CDX_INT_FREESPACE / ( pTag->uiLen + 8 );
|
||
pTag->OptFlags = pHeader.indexOpt;
|
||
pTag->UniqueKey = ( pTag->OptFlags & CDX_TYPE_UNIQUE );
|
||
pTag->Temporary = ( pTag->OptFlags & CDX_TYPE_TEMPORARY );
|
||
pTag->Custom = ( pTag->OptFlags & CDX_TYPE_CUSTOM );
|
||
pTag->AscendKey = pTag->UsrAscend = ( HB_GET_LE_USHORT( pHeader.ascendFlg ) == 0 );
|
||
pTag->UsrUnique = FALSE;
|
||
pTag->KeyExpr = ( char * ) hb_xgrab( CDX_MAXKEY + 1 );
|
||
/* QUESTION: Is UPPER a valid operation here?
|
||
* This will break expressions like:
|
||
* somefield+'lowerletter'+otherfield
|
||
* TODO:
|
||
*/
|
||
hb_strncpyUpper( pTag->KeyExpr, ( char * ) pHeader.keyExpPool, CDX_MAXKEY );
|
||
|
||
if ( ( pTag->OptFlags & CDX_TYPE_STRUCTURE ) || pTag->KeyExpr[ 0 ] == 0 )
|
||
return;
|
||
|
||
SELF_COMPILE( ( AREAP ) pTag->pIndex->pArea, ( BYTE * ) pTag->KeyExpr );
|
||
/* TODO: RT error if SELF_COMPILE return FAILURE */
|
||
pTag->pKeyItem = pTag->pIndex->pArea->valResult;
|
||
pTag->pIndex->pArea->valResult = NULL;
|
||
/* Get a blank record before testing expression */
|
||
ulRecNo = pTag->pIndex->pArea->ulRecNo;
|
||
SELF_GOTO( ( AREAP ) pTag->pIndex->pArea, 0 );
|
||
hb_macroRun( ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pKeyItem ) );
|
||
switch( hb_itemType( hb_stackItemFromTop( -1 ) ) )
|
||
{
|
||
case HB_IT_INTEGER:
|
||
case HB_IT_LONG:
|
||
#ifndef HB_LONG_LONG_OFF
|
||
case HB_IT_LONGLONG:
|
||
#endif
|
||
case HB_IT_DOUBLE:
|
||
pTag->uiType = 'N';
|
||
pTag->uiLen = 8;
|
||
break;
|
||
|
||
case HB_IT_DATE:
|
||
pTag->uiType = 'D';
|
||
pTag->uiLen = 8;
|
||
break;
|
||
|
||
case HB_IT_LOGICAL:
|
||
pTag->uiType = 'L';
|
||
pTag->uiLen = 1;
|
||
break;
|
||
|
||
case HB_IT_STRING:
|
||
pTag->uiType = 'C';
|
||
/* TODO: is this safe? */
|
||
/* pTag->uiLen = HB_CDXMAXKEY( ( hb_stackItemFromTop( -1 ) )->item.asString.length ); */
|
||
break;
|
||
}
|
||
hb_stackPop(); /* pop macro evaluated value */
|
||
if ( pTag->uiType == 'C' )
|
||
hb_cdxMakeSortTab( pTag->pIndex->pArea );
|
||
|
||
pTag->nField = hb_rddFieldIndex( ( AREAP ) pTag->pIndex->pArea, pTag->KeyExpr );
|
||
|
||
/* Check if there is a FOR expression CDX_TYPE_FORFILTER */
|
||
if ( pHeader.keyExpPool[ strlen( pTag->KeyExpr ) + 1 ] != 0 )
|
||
{
|
||
pTag->ForExpr = ( char * ) hb_xgrab( CDX_MAXKEY + 1 );
|
||
/* TODO: Uppering is bad */
|
||
hb_strncpyUpper( pTag->ForExpr, ( const char * ) pHeader.keyExpPool +
|
||
strlen( pTag->KeyExpr ) + 1, CDX_MAXKEY );
|
||
SELF_COMPILE( ( AREAP ) pTag->pIndex->pArea, ( BYTE * ) pTag->ForExpr );
|
||
/* TODO: RT error if SELF_COMPILE return FAILURE */
|
||
pTag->pForItem = pTag->pIndex->pArea->valResult;
|
||
pTag->pIndex->pArea->valResult = NULL;
|
||
pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pForItem );
|
||
hb_macroRun( pMacro );
|
||
if ( hb_itemType( hb_stackItemFromTop( -1 ) ) != HB_IT_LOGICAL )
|
||
{
|
||
hb_macroDelete( pMacro );
|
||
hb_itemRelease( pTag->pForItem );
|
||
pTag->pForItem = NULL;
|
||
hb_xfree( pTag->ForExpr );
|
||
pTag->ForExpr = NULL;
|
||
}
|
||
hb_stackPop();
|
||
}
|
||
SELF_GOTO( ( AREAP ) pTag->pIndex->pArea, ulRecNo );
|
||
}
|
||
|
||
/*
|
||
* Creates a new structure with a tag information
|
||
* TagHdr = offset of index page where a tag header is stored
|
||
* if CDX_DUMMYNODE then allocate space ofor a new tag header
|
||
*/
|
||
static LPCDXTAG hb_cdxTagNew( LPCDXINDEX pIndex, char *szTagName, ULONG TagHdr )
|
||
{
|
||
LPCDXTAG pTag;
|
||
|
||
pTag = ( LPCDXTAG ) hb_xgrab( sizeof( CDXTAG ) );
|
||
memset( pTag, 0, sizeof( CDXTAG ) );
|
||
pTag->szName = ( char * ) hb_xgrab( CDX_MAXTAGNAMELEN + 1 );
|
||
hb_strncpyUpperTrim( pTag->szName, szTagName, CDX_MAXTAGNAMELEN );
|
||
pTag->pIndex = pIndex;
|
||
pTag->AscendKey = pTag->UsrAscend = TRUE;
|
||
pTag->UsrUnique = FALSE;
|
||
pTag->uiType = 'C';
|
||
pTag->CurKey = hb_cdxKeyNew();
|
||
if ( TagHdr == CDX_DUMMYNODE )
|
||
{
|
||
pTag->TagBlock = hb_cdxIndexGetAvailPage( pIndex, TRUE );
|
||
pTag->TagChanged = TRUE;
|
||
pTag->OptFlags = CDX_TYPE_COMPACT | CDX_TYPE_COMPOUND;
|
||
}
|
||
else
|
||
{
|
||
pTag->TagBlock = TagHdr;
|
||
hb_cdxTagLoad( pTag );
|
||
}
|
||
return pTag;
|
||
}
|
||
|
||
/*
|
||
* release structure with a tag information from memory
|
||
*/
|
||
static void hb_cdxTagFree( LPCDXTAG pTag )
|
||
{
|
||
if ( pTag->RootPage != NULL )
|
||
{
|
||
hb_cdxPageFree( pTag->RootPage, FALSE );
|
||
pTag->RootPage = NULL;
|
||
}
|
||
hb_cdxTagPoolFlush( pTag );
|
||
hb_cdxTagPoolFree( pTag, 0 );
|
||
if ( pTag->TagChanged )
|
||
hb_cdxTagHeaderStore( pTag );
|
||
if ( pTag->szName != NULL )
|
||
hb_xfree( pTag->szName );
|
||
if ( pTag->KeyExpr != NULL )
|
||
hb_xfree( pTag->KeyExpr );
|
||
if ( pTag->pKeyItem != NULL )
|
||
{
|
||
if ( hb_itemType( pTag->pKeyItem ) != HB_IT_BLOCK )
|
||
hb_macroDelete( ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pKeyItem ) );
|
||
hb_itemRelease( pTag->pKeyItem );
|
||
}
|
||
if ( pTag->ForExpr != NULL )
|
||
hb_xfree( pTag->ForExpr );
|
||
if ( pTag->pForItem != NULL )
|
||
{
|
||
if ( hb_itemType( pTag->pForItem ) != HB_IT_BLOCK )
|
||
hb_macroDelete( ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pForItem ) );
|
||
hb_itemRelease( pTag->pForItem );
|
||
}
|
||
hb_cdxKeyFree( pTag->CurKey );
|
||
if ( pTag->HotKey )
|
||
hb_cdxKeyFree( pTag->HotKey );
|
||
hb_cdxTagClearScope( pTag, 0);
|
||
hb_cdxTagClearScope( pTag, 1);
|
||
hb_xfree( pTag );
|
||
}
|
||
|
||
/*
|
||
* close Tag (free used pages into page pool)
|
||
*/
|
||
static void hb_cdxTagClose( LPCDXTAG pTag )
|
||
{
|
||
if ( pTag->RootPage != NULL )
|
||
{
|
||
hb_cdxPageFree( pTag->RootPage, FALSE );
|
||
pTag->RootPage = NULL;
|
||
}
|
||
if ( pTag->TagChanged )
|
||
{
|
||
hb_cdxTagHeaderStore( pTag );
|
||
}
|
||
}
|
||
|
||
/*
|
||
* (re)open Tag
|
||
*/
|
||
static void hb_cdxTagOpen( LPCDXTAG pTag )
|
||
{
|
||
CDXTAGHEADER tagHeader;
|
||
|
||
if ( !pTag->RootPage )
|
||
{
|
||
hb_cdxIndexPageRead( pTag->pIndex, pTag->TagBlock, (BYTE *) &tagHeader, sizeof( CDXTAGHEADER ) );
|
||
pTag->RootBlock = HB_GET_LE_ULONG( tagHeader.rootPtr );
|
||
if ( pTag->RootBlock && pTag->RootBlock != CDX_DUMMYNODE )
|
||
pTag->RootPage = hb_cdxPageNew( pTag, NULL, pTag->RootBlock );
|
||
if ( !pTag->RootPage )
|
||
hb_cdxErrInternal("hb_cdxTagOpen: index corrupted");
|
||
}
|
||
}
|
||
|
||
/*
|
||
* free Tag pages from cache
|
||
*/
|
||
static void hb_cdxTagPoolFree( LPCDXTAG pTag, int nPagesLeft )
|
||
{
|
||
LPCDXPAGE pPage, pPageNext;
|
||
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxTagPoolCheck( pTag );
|
||
#endif
|
||
pPage = pTag->pagePool;
|
||
while ( nPagesLeft && pPage )
|
||
{
|
||
pPage = pPage->pPoolNext;
|
||
nPagesLeft--;
|
||
}
|
||
while ( pPage )
|
||
{
|
||
pPageNext = pPage->pPoolNext;
|
||
if ( ! pPage->bUsed )
|
||
{
|
||
hb_cdxPageFree( pPage, TRUE );
|
||
}
|
||
pPage = pPageNext;
|
||
}
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxTagPoolCheck( pTag );
|
||
#endif
|
||
}
|
||
|
||
/*
|
||
* write all changed pages in tag cache
|
||
*/
|
||
static void hb_cdxTagPoolFlush( LPCDXTAG pTag )
|
||
{
|
||
LPCDXPAGE pPage;
|
||
|
||
pPage = pTag->pagePool;
|
||
while ( pPage )
|
||
{
|
||
if ( pPage->fChanged )
|
||
{
|
||
hb_cdxPageStore( pPage );
|
||
}
|
||
pPage = pPage->pPoolNext;
|
||
}
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
hb_cdxTagPoolCheck( pTag );
|
||
#endif
|
||
}
|
||
|
||
/*
|
||
* retrive CurKey from current Tag possition
|
||
*/
|
||
static void hb_cdxSetCurKey( LPCDXPAGE pPage )
|
||
{
|
||
while ( pPage->Child )
|
||
pPage = pPage->Child;
|
||
|
||
hb_cdxKeyPut( pPage->TagParent->CurKey,
|
||
hb_cdxPageGetKeyVal( pPage, pPage->iCurKey ),
|
||
pPage->TagParent->uiLen,
|
||
hb_cdxPageGetKeyRec( pPage, pPage->iCurKey ) );
|
||
}
|
||
|
||
/*
|
||
* seek given Key in the Page or in its children
|
||
*/
|
||
static int hb_cdxPageSeekKey( LPCDXPAGE pPage, LPCDXKEY pKey, ULONG ulKeyRec, BOOL fExact )
|
||
{
|
||
int l, r, n, k;
|
||
BOOL fLeaf = ( pPage->PageType & CDX_NODE_LEAF ) != 0;
|
||
|
||
if ( fLeaf && !pPage->pKeyBuf && pPage->iKeys > 0 )
|
||
{
|
||
SHORT iLen = pPage->TagParent->uiLen + 6;
|
||
BYTE *pKeyBuf = (BYTE *) hb_xgrab( pPage->iKeys * iLen );
|
||
hb_cdxPageLeafDecode( pPage, pKeyBuf );
|
||
pPage->pKeyBuf = pKeyBuf;
|
||
}
|
||
|
||
k = ( ulKeyRec == CDX_MAX_REC_NUM ) ? -1 : 1;
|
||
n = -1;
|
||
l = 0;
|
||
r = pPage->iKeys - 1;
|
||
while ( l < r )
|
||
{
|
||
n = (l + r ) >> 1;
|
||
k = hb_cdxValCompare( pPage->TagParent, pKey->val, pKey->len,
|
||
hb_cdxPageGetKeyVal( pPage, n ),
|
||
(BYTE) pPage->TagParent->uiLen, fExact );
|
||
if ( k == 0 )
|
||
{
|
||
if ( ulKeyRec == CDX_MAX_REC_NUM )
|
||
k = 1;
|
||
else if ( ulKeyRec != CDX_IGNORE_REC_NUM )
|
||
{
|
||
ULONG ulRec = hb_cdxPageGetKeyRec( pPage, n );
|
||
if ( ulKeyRec > ulRec )
|
||
k = 1;
|
||
else if ( ulKeyRec < ulRec )
|
||
k = -1;
|
||
}
|
||
}
|
||
if ( k > 0 )
|
||
l = n + 1;
|
||
else
|
||
r = n;
|
||
}
|
||
pPage->iCurKey = l;
|
||
if ( r < 0 )
|
||
return k;
|
||
|
||
if ( !fLeaf )
|
||
{
|
||
hb_cdxPageGetChild( pPage );
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( memcmp( hb_cdxPageGetKeyVal( pPage, pPage->iCurKey ),
|
||
hb_cdxPageGetKeyVal( pPage->Child, pPage->Child->iKeys-1 ),
|
||
pPage->TagParent->uiLen ) != 0 ||
|
||
hb_cdxPageGetKeyRec( pPage, pPage->iCurKey ) !=
|
||
hb_cdxPageGetKeyRec( pPage->Child, pPage->Child->iKeys-1 ) )
|
||
{
|
||
printf("\r\nparent=%lx, iKey=%d, rec=%ld", pPage->Page, pPage->iCurKey, hb_cdxPageGetKeyRec( pPage, pPage->iCurKey ));
|
||
printf("\r\n child=%lx, iKey=%d, rec=%ld", pPage->Child->Page, pPage->Child->iKeys-1, hb_cdxPageGetKeyRec( pPage->Child, pPage->Child->iKeys-1 ));
|
||
fflush(stdout);
|
||
hb_cdxErrInternal("hb_cdxPageSeekKey: wrong parent key.");
|
||
}
|
||
#endif
|
||
k = hb_cdxPageSeekKey( pPage->Child, pKey, ulKeyRec, fExact );
|
||
}
|
||
else if ( l != n || ulKeyRec == CDX_MAX_REC_NUM )
|
||
{
|
||
k = hb_cdxValCompare( pPage->TagParent, pKey->val, pKey->len,
|
||
hb_cdxPageGetKeyVal( pPage, pPage->iCurKey ),
|
||
(BYTE) pPage->TagParent->uiLen, fExact );
|
||
if ( k == 0 && ulKeyRec != CDX_MAX_REC_NUM &&
|
||
ulKeyRec != CDX_IGNORE_REC_NUM )
|
||
{
|
||
ULONG ulRec = hb_cdxPageGetKeyRec( pPage, pPage->iCurKey );
|
||
if ( ulKeyRec > ulRec )
|
||
k = 1;
|
||
else if ( ulKeyRec < ulRec )
|
||
k = -1;
|
||
}
|
||
}
|
||
if ( ulKeyRec == CDX_MAX_REC_NUM )
|
||
{
|
||
if ( pPage->iCurKey > 0 && k < 0 )
|
||
{
|
||
pPage->iCurKey--;
|
||
if ( !fLeaf )
|
||
{
|
||
hb_cdxPageGetChild( pPage );
|
||
k = hb_cdxPageSeekKey( pPage->Child, pKey, ulKeyRec, fExact );
|
||
}
|
||
else
|
||
k = hb_cdxValCompare( pPage->TagParent, pKey->val, pKey->len,
|
||
hb_cdxPageGetKeyVal( pPage, pPage->iCurKey ),
|
||
(BYTE) pPage->TagParent->uiLen, fExact );
|
||
}
|
||
}
|
||
else if ( k > 0 && fLeaf )
|
||
pPage->iCurKey++;
|
||
return k;
|
||
}
|
||
|
||
/*
|
||
* read Top Key from Page or its children
|
||
*/
|
||
static BOOL hb_cdxPageReadTopKey( LPCDXPAGE pPage )
|
||
{
|
||
while ( ( pPage->PageType & CDX_NODE_LEAF ) == 0 && pPage->iKeys > 0 )
|
||
{
|
||
pPage->iCurKey = 0;
|
||
hb_cdxPageGetChild( pPage );
|
||
pPage = pPage->Child;
|
||
}
|
||
if ( pPage->iKeys == 0 )
|
||
return FALSE;
|
||
pPage->iCurKey = 0;
|
||
|
||
hb_cdxSetCurKey( pPage );
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* read Bottom Key from Page or its children
|
||
*/
|
||
static BOOL hb_cdxPageReadBottomKey( LPCDXPAGE pPage )
|
||
{
|
||
while ( ( pPage->PageType & CDX_NODE_LEAF ) == 0 && pPage->iKeys > 0 )
|
||
{
|
||
pPage->iCurKey = pPage->iKeys - 1;
|
||
hb_cdxPageGetChild( pPage );
|
||
pPage = pPage->Child;
|
||
}
|
||
if ( pPage->iKeys == 0 )
|
||
return FALSE;
|
||
pPage->iCurKey = pPage->iKeys - 1;
|
||
|
||
hb_cdxSetCurKey( pPage );
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* read Previous Key from Page or its children
|
||
*/
|
||
static BOOL hb_cdxPageReadPrevKey( LPCDXPAGE pPage )
|
||
{
|
||
LPCDXPAGE pOwnerPage = NULL;
|
||
|
||
while ( pPage->Child )
|
||
{
|
||
pOwnerPage = pPage;
|
||
pPage = pPage->Child;
|
||
}
|
||
pPage->iCurKey--;
|
||
while ( pPage->iCurKey < 0 )
|
||
{
|
||
if ( pPage->Left == CDX_DUMMYNODE || !pOwnerPage )
|
||
{
|
||
pPage->iCurKey = 0;
|
||
if ( pPage->iKeys > 0 )
|
||
hb_cdxSetCurKey( pPage );
|
||
return FALSE;
|
||
}
|
||
pOwnerPage->Child = hb_cdxPageNew( pPage->TagParent, pPage->Owner, pPage->Left );
|
||
hb_cdxPageFree( pPage, !pPage->fChanged );
|
||
pPage = pOwnerPage->Child;
|
||
pPage->iCurKey = pPage->iKeys - 1;
|
||
}
|
||
|
||
hb_cdxSetCurKey( pPage );
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* read Next Key from Page or its children
|
||
*/
|
||
static BOOL hb_cdxPageReadNextKey( LPCDXPAGE pPage )
|
||
{
|
||
LPCDXPAGE pOwnerPage = NULL;
|
||
|
||
while ( pPage->Child )
|
||
{
|
||
pOwnerPage = pPage;
|
||
pPage = pPage->Child;
|
||
}
|
||
pPage->iCurKey++;
|
||
while ( pPage->iCurKey >= pPage->iKeys )
|
||
{
|
||
if ( pPage->Right == CDX_DUMMYNODE || !pOwnerPage )
|
||
{
|
||
pPage->iCurKey = pPage->iKeys;
|
||
return FALSE;
|
||
}
|
||
pOwnerPage->Child = hb_cdxPageNew( pPage->TagParent, pPage->Owner, pPage->Right );
|
||
hb_cdxPageFree( pPage, !pPage->fChanged );
|
||
pPage = pOwnerPage->Child;
|
||
pPage->iCurKey = 0;
|
||
}
|
||
|
||
hb_cdxSetCurKey( pPage );
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* read Previous Unique Key from Page or its children
|
||
*/
|
||
static BOOL hb_cdxPageReadPrevUniqKey( LPCDXPAGE pPage )
|
||
{
|
||
LPCDXPAGE pOwnerPage = NULL;
|
||
|
||
while ( pPage->Child )
|
||
{
|
||
pOwnerPage = pPage;
|
||
pPage = pPage->Child;
|
||
}
|
||
while ( pPage->iCurKey < 0 || memcmp( pPage->TagParent->CurKey->val, hb_cdxPageGetKeyVal( pPage, pPage->iCurKey ), pPage->TagParent->uiLen ) == 0 )
|
||
{
|
||
if ( pPage->iCurKey > 0 )
|
||
pPage->iCurKey--;
|
||
else
|
||
{
|
||
if ( pPage->Left == CDX_DUMMYNODE || !pOwnerPage )
|
||
{
|
||
pPage->iCurKey = 0;
|
||
if ( pPage->iKeys > 0 )
|
||
hb_cdxSetCurKey( pPage );
|
||
return FALSE;
|
||
}
|
||
pOwnerPage->Child = hb_cdxPageNew( pPage->TagParent, pPage->Owner, pPage->Left );
|
||
hb_cdxPageFree( pPage, !pPage->fChanged );
|
||
pPage = pOwnerPage->Child;
|
||
pPage->iCurKey = pPage->iKeys - 1;
|
||
}
|
||
}
|
||
|
||
hb_cdxSetCurKey( pPage );
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* read Next Unique Key from Page or its children
|
||
*/
|
||
static BOOL hb_cdxPageReadNextUniqKey( LPCDXPAGE pPage )
|
||
{
|
||
LPCDXPAGE pOwnerPage = NULL;
|
||
// BYTE pbVal[CDX_MAXKEY];
|
||
|
||
while ( pPage->Child )
|
||
{
|
||
pOwnerPage = pPage;
|
||
pPage = pPage->Child;
|
||
}
|
||
// memcpy( pbVal, hb_cdxPageGetKeyVal( pPage, pPage->iCurKey ), pPage->TagParent->uiLen );
|
||
// pPage->iCurKey++;
|
||
// while ( pPage->iCurKey >= pPage->iKeys || memcmp( pbVal, hb_cdxPageGetKeyVal( pPage, pPage->iCurKey ), pPage->TagParent->uiLen ) == 0 )
|
||
while ( pPage->iCurKey >= pPage->iKeys || memcmp( pPage->TagParent->CurKey->val, hb_cdxPageGetKeyVal( pPage, pPage->iCurKey ), pPage->TagParent->uiLen ) == 0 )
|
||
{
|
||
if ( pPage->iCurKey < pPage->iKeys - 1 )
|
||
pPage->iCurKey++;
|
||
else
|
||
{
|
||
if ( pPage->Right == CDX_DUMMYNODE || !pOwnerPage )
|
||
{
|
||
pPage->iCurKey = pPage->iKeys - 1;
|
||
if ( pPage->iKeys > 0 )
|
||
hb_cdxSetCurKey( pPage );
|
||
return FALSE;
|
||
}
|
||
pOwnerPage->Child = hb_cdxPageNew( pPage->TagParent, pPage->Owner, pPage->Right );
|
||
hb_cdxPageFree( pPage, !pPage->fChanged );
|
||
pPage = pOwnerPage->Child;
|
||
pPage->iCurKey = 0;
|
||
}
|
||
}
|
||
hb_cdxSetCurKey( pPage );
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* read the TOP/BOTTOM/NEXT/PREVIOUS Key from Tag
|
||
*/
|
||
static void hb_cdxTagKeyRead( LPCDXTAG pTag, BYTE bTypRead )
|
||
{
|
||
BOOL fAfter = FALSE, fBof, fEof;
|
||
|
||
pTag->CurKey->rec = 0;
|
||
pTag->fRePos = FALSE;
|
||
hb_cdxTagOpen( pTag );
|
||
|
||
if ( pTag->UsrUnique )
|
||
{
|
||
switch( bTypRead )
|
||
{
|
||
case NEXT_RECORD:
|
||
bTypRead = NXTU_RECORD;
|
||
break;
|
||
|
||
case PREV_RECORD:
|
||
bTypRead = PRVU_RECORD;
|
||
case BTTM_RECORD:
|
||
fAfter = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
if ( pTag->UsrAscend )
|
||
{
|
||
fBof = pTag->TagBOF;
|
||
fEof = pTag->TagEOF;
|
||
}
|
||
else
|
||
{
|
||
fBof = pTag->TagEOF;
|
||
fEof = pTag->TagBOF;
|
||
switch( bTypRead )
|
||
{
|
||
case TOP_RECORD:
|
||
bTypRead = BTTM_RECORD;
|
||
break;
|
||
|
||
case BTTM_RECORD:
|
||
bTypRead = TOP_RECORD;
|
||
break;
|
||
|
||
case PREV_RECORD:
|
||
bTypRead = NEXT_RECORD;
|
||
break;
|
||
|
||
case NEXT_RECORD:
|
||
bTypRead = PREV_RECORD;
|
||
break;
|
||
|
||
case PRVU_RECORD:
|
||
bTypRead = NXTU_RECORD;
|
||
break;
|
||
|
||
case NXTU_RECORD:
|
||
bTypRead = PRVU_RECORD;
|
||
break;
|
||
}
|
||
}
|
||
//fBof = fEof = FALSE;
|
||
switch( bTypRead )
|
||
{
|
||
case TOP_RECORD:
|
||
fBof = fEof = !hb_cdxPageReadTopKey( pTag->RootPage );
|
||
break;
|
||
|
||
case BTTM_RECORD:
|
||
fBof = fEof = !hb_cdxPageReadBottomKey( pTag->RootPage );
|
||
break;
|
||
|
||
case PREV_RECORD:
|
||
if ( !fBof )
|
||
fBof = !hb_cdxPageReadPrevKey( pTag->RootPage );
|
||
break;
|
||
|
||
case NEXT_RECORD:
|
||
if ( !fEof )
|
||
fEof = !hb_cdxPageReadNextKey( pTag->RootPage );
|
||
break;
|
||
|
||
case PRVU_RECORD:
|
||
if ( !fBof )
|
||
fBof = !hb_cdxPageReadPrevUniqKey( pTag->RootPage );
|
||
break;
|
||
|
||
case NXTU_RECORD:
|
||
if ( !fEof )
|
||
fEof = !hb_cdxPageReadNextUniqKey( pTag->RootPage );
|
||
break;
|
||
}
|
||
|
||
if ( fEof )
|
||
pTag->CurKey->rec = 0;
|
||
else if ( fAfter && !fBof )
|
||
{
|
||
if ( pTag->UsrAscend )
|
||
{
|
||
if ( hb_cdxPageReadPrevUniqKey( pTag->RootPage ) )
|
||
hb_cdxPageReadNextKey( pTag->RootPage );
|
||
}
|
||
else
|
||
{
|
||
if ( hb_cdxPageReadNextUniqKey( pTag->RootPage ) )
|
||
hb_cdxPageReadPrevKey( pTag->RootPage );
|
||
}
|
||
}
|
||
|
||
if ( pTag->UsrAscend )
|
||
{
|
||
pTag->TagBOF = fBof;
|
||
pTag->TagEOF = fEof;
|
||
}
|
||
else
|
||
{
|
||
pTag->TagBOF = fEof;
|
||
pTag->TagEOF = fBof;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* find pKey in pTag return 0 or TagNO
|
||
*/
|
||
static ULONG hb_cdxTagKeyFind( LPCDXTAG pTag, LPCDXKEY pKey )
|
||
{
|
||
int K;
|
||
ULONG ulKeyRec = pKey->rec;
|
||
|
||
if ( pTag->UsrUnique )
|
||
{
|
||
if ( pTag->UsrAscend )
|
||
{
|
||
if ( ulKeyRec == CDX_MAX_REC_NUM )
|
||
ulKeyRec = CDX_IGNORE_REC_NUM;
|
||
}
|
||
else if ( ulKeyRec == CDX_IGNORE_REC_NUM )
|
||
ulKeyRec = CDX_MAX_REC_NUM;
|
||
}
|
||
|
||
pTag->CurKey->rec = 0;
|
||
pTag->fRePos = FALSE;
|
||
hb_cdxTagOpen( pTag );
|
||
|
||
pTag->TagBOF = pTag->TagEOF = FALSE;
|
||
K = hb_cdxPageSeekKey( pTag->RootPage, pKey, ulKeyRec, FALSE );
|
||
if ( ulKeyRec == CDX_MAX_REC_NUM )
|
||
K = - K;
|
||
|
||
if ( K > 0 )
|
||
pTag->TagEOF = TRUE;
|
||
else
|
||
{
|
||
hb_cdxSetCurKey( pTag->RootPage );
|
||
if ( K == 0 )
|
||
return pTag->CurKey->rec;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* add the Key into the Tag
|
||
*/
|
||
static void hb_cdxTagKeyAdd( LPCDXTAG pTag, LPCDXKEY pKey )
|
||
{
|
||
BOOL fFound;
|
||
|
||
hb_cdxTagOpen( pTag );
|
||
fFound = ( hb_cdxPageSeekKey( pTag->RootPage, pKey,
|
||
pTag->UniqueKey ? CDX_IGNORE_REC_NUM : pKey->rec,
|
||
TRUE ) == 0 );
|
||
if ( ! fFound )
|
||
{
|
||
#ifdef HB_CDX_DBGUPDT
|
||
cdxTmpStackSize = 0;
|
||
#endif
|
||
hb_cdxPageKeyInsert( pTag->RootPage, pKey );
|
||
#ifdef HB_CDX_DBGUPDT
|
||
if ( cdxTmpStackSize > cdxStackSize )
|
||
cdxStackSize = cdxTmpStackSize;
|
||
#endif
|
||
/* TODO: !!! remove when page leaf balance can save CurKey */
|
||
hb_cdxTagKeyFind( pTag, pKey );
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Reorder the Tag list by their position in index file (not names)
|
||
* to be Clipper compatible
|
||
*/
|
||
static void hb_cdxReorderTagList( LPCDXTAG * TagListPtr )
|
||
{
|
||
LPCDXTAG *pTagPtr, pTagTmp;
|
||
BOOL fRepeat = TRUE;
|
||
|
||
while ( fRepeat )
|
||
{
|
||
fRepeat = FALSE;
|
||
pTagPtr = TagListPtr;
|
||
while ( *pTagPtr && (*pTagPtr)->pNext )
|
||
{
|
||
if ( (*pTagPtr)->TagBlock > (*pTagPtr)->pNext->TagBlock )
|
||
{
|
||
pTagTmp = (*pTagPtr);
|
||
(*pTagPtr) = (*pTagPtr)->pNext;
|
||
pTagTmp->pNext = (*pTagPtr)->pNext;
|
||
(*pTagPtr)->pNext = pTagTmp;
|
||
fRepeat = TRUE;
|
||
}
|
||
pTagPtr = &(*pTagPtr)->pNext;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* create new order header, store it and then make an order
|
||
*/
|
||
static void hb_cdxTagIndexTagNew( LPCDXTAG pTag,
|
||
char * KeyExp, PHB_ITEM pKeyItem,
|
||
BYTE bType, USHORT uiLen,
|
||
char * ForExp, PHB_ITEM pForItem,
|
||
BOOL fAscnd, BOOL fUniq, BOOL fCustom )
|
||
{
|
||
if ( bType == 'C' )
|
||
hb_cdxMakeSortTab( pTag->pIndex->pArea );
|
||
if ( KeyExp != NULL )
|
||
{
|
||
pTag->KeyExpr = ( char * ) hb_xgrab( CDX_MAXKEY + 1 );
|
||
/* TODO: !!! upering is buggy */
|
||
hb_strncpyUpper( pTag->KeyExpr, KeyExp, CDX_MAXKEY );
|
||
pTag->nField = hb_rddFieldIndex( (AREAP) pTag->pIndex->pArea, pTag->KeyExpr );
|
||
}
|
||
pTag->pKeyItem = pKeyItem;
|
||
if ( ForExp != NULL )
|
||
{
|
||
pTag->ForExpr = ( char * ) hb_xgrab( CDX_MAXKEY + 1 );
|
||
/* TODO: !!! upering is buggy */
|
||
hb_strncpyUpper( pTag->ForExpr, ForExp, CDX_MAXKEY );
|
||
}
|
||
pTag->pForItem = pForItem;
|
||
pTag->AscendKey = pTag->UsrAscend = fAscnd;
|
||
pTag->UniqueKey = fUniq;
|
||
pTag->UsrUnique = FALSE;
|
||
pTag->Custom = fCustom;
|
||
pTag->uiType = bType;
|
||
pTag->uiLen = uiLen;
|
||
pTag->MaxKeys = CDX_INT_FREESPACE / ( uiLen + 8 );
|
||
pTag->TagChanged = TRUE;
|
||
hb_cdxTagDoIndex( pTag );
|
||
}
|
||
|
||
/*
|
||
* free page and all child pages
|
||
*/
|
||
static void hb_cdxIndexFreePages( LPCDXPAGE pPage )
|
||
{
|
||
if ( ( pPage->PageType & CDX_NODE_LEAF ) == 0 )
|
||
{
|
||
LPCDXPAGE pChildPage;
|
||
SHORT iKey;
|
||
|
||
for ( iKey = 0; iKey < pPage->iKeys; iKey++ )
|
||
{
|
||
pChildPage = hb_cdxPageNew( pPage->TagParent, NULL,
|
||
hb_cdxPageGetKeyPage( pPage, iKey ) );
|
||
if ( pChildPage )
|
||
hb_cdxIndexFreePages( pChildPage );
|
||
}
|
||
}
|
||
pPage->PageType = CDX_NODE_UNUSED;
|
||
hb_cdxPageFree( pPage, FALSE );
|
||
}
|
||
|
||
/*
|
||
* remove Tag from Bag
|
||
*/
|
||
static void hb_cdxIndexDelTag( LPCDXINDEX pIndex, char * szTagName )
|
||
{
|
||
LPCDXTAG *pTagPtr = &pIndex->TagList;
|
||
|
||
while ( *pTagPtr && hb_stricmp( (*pTagPtr)->szName, szTagName ) != 0 )
|
||
pTagPtr = &(*pTagPtr)->pNext;
|
||
|
||
if ( *pTagPtr )
|
||
{
|
||
LPCDXTAG pTag = *pTagPtr;
|
||
LPCDXKEY pKey = hb_cdxKeyPutC( NULL, szTagName, CDX_MAXTAGNAMELEN, pTag->TagBlock );
|
||
if ( hb_cdxTagKeyFind( pIndex->pCompound, pKey ) > 0 )
|
||
{
|
||
hb_cdxPageKeyDelete( pIndex->pCompound->RootPage );
|
||
if ( pTag != pIndex->TagList || pTag->pNext != NULL )
|
||
{
|
||
LPCDXPAGE pPage;
|
||
|
||
hb_cdxTagOpen( pTag );
|
||
pPage = pTag->RootPage;
|
||
hb_cdxTagClose( pTag );
|
||
if ( pPage )
|
||
hb_cdxIndexFreePages( pPage );
|
||
pTag->TagChanged = FALSE;
|
||
hb_cdxIndexPutAvailPage( pIndex, pTag->TagBlock, TRUE );
|
||
}
|
||
}
|
||
*pTagPtr = pTag->pNext;
|
||
hb_cdxTagFree( pTag );
|
||
hb_cdxKeyFree( pKey );
|
||
}
|
||
}
|
||
|
||
/*
|
||
* add tag to order bag
|
||
*/
|
||
static LPCDXTAG hb_cdxIndexAddTag( LPCDXINDEX pIndex, char * szTagName,
|
||
char * szKeyExp, PHB_ITEM pKeyItem,
|
||
BYTE bType, USHORT uiLen,
|
||
char * szForExp, PHB_ITEM pForItem,
|
||
BOOL fAscend, BOOL fUnique, BOOL fCustom )
|
||
{
|
||
LPCDXTAG pTag, *pTagPtr;
|
||
LPCDXKEY pKey;
|
||
|
||
/* Delete previous tag first to free the place for new one
|
||
* its redundant Tag should be already deleted
|
||
*/
|
||
hb_cdxIndexDelTag( pIndex, szTagName );
|
||
|
||
/* Create new tag an add to tag list */
|
||
pTag = hb_cdxTagNew( pIndex, szTagName, CDX_DUMMYNODE );
|
||
hb_cdxTagIndexTagNew( pTag, szKeyExp, pKeyItem, bType, uiLen,
|
||
szForExp, pForItem,
|
||
fAscend, fUnique, fCustom );
|
||
pTagPtr = &pIndex->TagList;
|
||
while ( *pTagPtr )
|
||
pTagPtr = &(*pTagPtr)->pNext;
|
||
*pTagPtr = pTag;
|
||
pKey = hb_cdxKeyPutC( NULL, szTagName, CDX_MAXTAGNAMELEN, pTag->TagBlock );
|
||
hb_cdxTagKeyAdd( pIndex->pCompound, pKey );
|
||
hb_cdxKeyFree( pKey );
|
||
return pTag;
|
||
}
|
||
|
||
/*
|
||
* rebuild from scratch all orders in index file
|
||
*/
|
||
static void hb_cdxIndexReindex( LPCDXINDEX pIndex )
|
||
{
|
||
LPCDXTAG pCompound, pTagList, pTag;
|
||
|
||
hb_cdxIndexLockWrite( pIndex );
|
||
hb_cdxIndexDiscardBuffers( pIndex );
|
||
|
||
pCompound = pIndex->pCompound;
|
||
pTagList = pIndex->TagList;
|
||
pIndex->pCompound = NULL;
|
||
pIndex->TagList = NULL;
|
||
|
||
pIndex->ulVersion = 0;
|
||
pIndex->nextAvail = 0;
|
||
pIndex->freePage = 0;
|
||
hb_fsSeek( pIndex->hFile, 0, FS_SET );
|
||
hb_fsWrite( pIndex->hFile, NULL, 0 );
|
||
|
||
/* Rebuild the compound (master) tag */
|
||
if ( pCompound )
|
||
{
|
||
pIndex->pCompound = hb_cdxTagNew( pIndex, pCompound->szName, CDX_DUMMYNODE );
|
||
pIndex->pCompound->OptFlags = CDX_TYPE_COMPACT | CDX_TYPE_COMPOUND | CDX_TYPE_STRUCTURE;;
|
||
hb_cdxTagIndexTagNew( pIndex->pCompound, NULL, NULL, 'C',
|
||
CDX_MAXTAGNAMELEN, NULL, NULL, TRUE, FALSE, FALSE );
|
||
hb_cdxTagFree( pCompound );
|
||
}
|
||
|
||
/* Rebuild each tag */
|
||
while ( pTagList )
|
||
{
|
||
pTag = pTagList;
|
||
hb_cdxIndexAddTag( pIndex, pTag->szName, pTag->KeyExpr, pTag->pKeyItem,
|
||
(BYTE) pTag->uiType, pTag->uiLen, pTag->ForExpr, pTag->pForItem,
|
||
pTag->AscendKey, pTag->UniqueKey, pTag->Custom );
|
||
pTagList = pTag->pNext;
|
||
pTag->pKeyItem = pTag->pForItem = NULL;
|
||
hb_cdxTagFree( pTag );
|
||
}
|
||
hb_cdxIndexUnLockWrite( pIndex );
|
||
}
|
||
|
||
/*
|
||
* create new index structure
|
||
*/
|
||
static LPCDXINDEX hb_cdxIndexNew( CDXAREAP pArea )
|
||
{
|
||
LPCDXINDEX pIndex;
|
||
|
||
pIndex = ( LPCDXINDEX ) hb_xgrab( sizeof( CDXINDEX ) );
|
||
memset( pIndex, 0, sizeof( CDXINDEX ) );
|
||
pIndex->hFile = FS_ERROR;
|
||
pIndex->pArea = pArea;
|
||
pIndex->nextAvail = CDX_DUMMYNODE;
|
||
return pIndex;
|
||
}
|
||
|
||
/*
|
||
* free (close) index and all tags in it
|
||
*/
|
||
static void hb_cdxIndexFree( LPCDXINDEX pIndex )
|
||
{
|
||
LPCDXTAG pTag;
|
||
|
||
/* Free List of Free Pages */
|
||
hb_cdxIndexDropAvailPage( pIndex );
|
||
|
||
/* Free Compound tag */
|
||
if ( pIndex->pCompound != NULL )
|
||
{
|
||
hb_cdxTagFree( pIndex->pCompound );
|
||
pIndex->pCompound = NULL;
|
||
}
|
||
|
||
/* Free all tags */
|
||
while ( pIndex->TagList )
|
||
{
|
||
pTag = pIndex->TagList;
|
||
pIndex->TagList = pTag->pNext;
|
||
hb_cdxTagFree( pTag );
|
||
}
|
||
/* Close file */
|
||
if ( pIndex->hFile != FS_ERROR )
|
||
hb_fsClose( pIndex->hFile );
|
||
|
||
if ( pIndex->fShared && ( pIndex->lockWrite || pIndex->lockRead ) )
|
||
hb_errInternal( 9104, "hb_cdxIndexFree: index file still locked.", "", "" );
|
||
#ifdef HB_CDX_DBGCODE
|
||
if ( pIndex->WrLck || pIndex->RdLck )
|
||
hb_errInternal( 9104, "hb_cdxIndexFree: index file still locked (*)", "", "" );
|
||
#endif
|
||
|
||
if ( pIndex->szFileName != NULL )
|
||
hb_xfree( pIndex->szFileName );
|
||
|
||
hb_xfree( pIndex );
|
||
}
|
||
|
||
/*
|
||
* load orders from index file
|
||
*/
|
||
static void hb_cdxIndexLoad( LPCDXINDEX pIndex, char * szBaseName )
|
||
{
|
||
LPCDXTAG TagList, * pTagPtr;
|
||
|
||
/* TODO: check if index file is not corrupted */
|
||
|
||
pIndex->fShared = pIndex->pArea->fShared;
|
||
pIndex->fReadonly = pIndex->pArea->fReadonly;
|
||
hb_cdxIndexLockRead( pIndex );
|
||
/* load the tags*/
|
||
pIndex->pCompound = hb_cdxTagNew( pIndex, szBaseName, 0L );
|
||
pIndex->pCompound->OptFlags = CDX_TYPE_COMPACT | CDX_TYPE_COMPOUND | CDX_TYPE_STRUCTURE;
|
||
TagList = NULL;
|
||
pTagPtr = &TagList;
|
||
hb_cdxTagKeyRead( pIndex->pCompound, TOP_RECORD );
|
||
while ( !pIndex->pCompound->TagEOF )
|
||
{
|
||
(*pTagPtr) = hb_cdxTagNew( pIndex, (char *) pIndex->pCompound->CurKey->val,
|
||
pIndex->pCompound->CurKey->rec );
|
||
pTagPtr = &(*pTagPtr)->pNext;
|
||
hb_cdxTagKeyRead( pIndex->pCompound, NEXT_RECORD );
|
||
}
|
||
hb_cdxIndexUnLockRead( pIndex );
|
||
hb_cdxReorderTagList( &TagList );
|
||
pTagPtr = &pIndex->TagList;
|
||
while ( *pTagPtr != NULL )
|
||
pTagPtr = &(*pTagPtr)->pNext;
|
||
(*pTagPtr) = TagList;
|
||
#ifdef HB_CDX_DSPDBG_INFO
|
||
hb_cdxDspTags( pIndex );
|
||
#endif
|
||
}
|
||
|
||
/*
|
||
* free (close) used indexes, if not fAll then keep structure index
|
||
*/
|
||
static void hb_cdxOrdListClear( CDXAREAP pArea, BOOL fAll, LPCDXINDEX pKeepInd )
|
||
{
|
||
HB_TRACE(HB_TR_DEBUG, ("hb_cdxOrdListClear(%p, %d)", pArea, (int) fAll));
|
||
|
||
if ( pArea->lpIndexes )
|
||
{
|
||
LPCDXINDEX pIndex, * pIndexPtr;
|
||
if ( !fAll )
|
||
{
|
||
/* TODO: we have to control this on open */
|
||
PHB_FNAME pFileNameDbf, pFileNameCdx;
|
||
pFileNameDbf = hb_fsFNameSplit( pArea->szDataFileName );
|
||
pFileNameCdx = hb_fsFNameSplit( pArea->lpIndexes->szFileName );
|
||
fAll = ( hb_stricmp( pFileNameDbf->szName, pFileNameCdx->szName ) != 0 );
|
||
hb_xfree( pFileNameDbf );
|
||
hb_xfree( pFileNameCdx );
|
||
}
|
||
pIndexPtr = fAll ? &pArea->lpIndexes : &pArea->lpIndexes->pNext;
|
||
while ( *pIndexPtr )
|
||
{
|
||
pIndex = *pIndexPtr;
|
||
if ( pKeepInd == pIndex )
|
||
pIndexPtr = &pIndex->pNext;
|
||
else
|
||
{
|
||
*pIndexPtr = pIndex->pNext;
|
||
hb_cdxIndexFree( pIndex );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* find order bag by its name
|
||
* TODO: This only checks for basename of bag,
|
||
* a complete (but reliable) test should be done to look for the same file
|
||
* druzus: if we allow to make more bugs with the same name -
|
||
* I'm not a fun of this
|
||
*/
|
||
static LPCDXINDEX hb_cdxFindBag( CDXAREAP pArea, char * szBagName )
|
||
{
|
||
LPCDXINDEX pIndex;
|
||
PHB_FNAME pFileName;
|
||
char * szBaseName;
|
||
|
||
pFileName = hb_fsFNameSplit( szBagName );
|
||
szBaseName = hb_strdup( pFileName->szName );
|
||
hb_strUpper( szBaseName, strlen(szBaseName) );
|
||
|
||
pIndex = pArea->lpIndexes;
|
||
while ( pIndex )
|
||
{
|
||
hb_xfree( pFileName );
|
||
pFileName = hb_fsFNameSplit( pIndex->szFileName );
|
||
hb_strUpper( pFileName->szName, strlen(pFileName->szName) );
|
||
if ( !hb_stricmp( pFileName->szName, szBaseName ) )
|
||
break;
|
||
pIndex = pIndex->pNext;
|
||
}
|
||
hb_xfree( pFileName );
|
||
hb_xfree( szBaseName );
|
||
return pIndex;
|
||
}
|
||
|
||
/*
|
||
* get Tag by number
|
||
*/
|
||
static LPCDXTAG hb_cdxGetTagByNumber( CDXAREAP pArea, USHORT uiTag )
|
||
{
|
||
LPCDXTAG pTag = NULL;
|
||
LPCDXINDEX pIndex = pArea->lpIndexes;
|
||
|
||
while ( uiTag && pIndex )
|
||
{
|
||
pTag = pIndex->TagList;
|
||
while ( uiTag && pTag )
|
||
{
|
||
if ( --uiTag )
|
||
pTag = pTag->pNext;
|
||
}
|
||
pIndex = pIndex->pNext;
|
||
}
|
||
return pTag;
|
||
}
|
||
|
||
/*
|
||
* get Tag number
|
||
*/
|
||
static USHORT hb_cdxGetTagNumber( CDXAREAP pArea, LPCDXTAG pFindTag )
|
||
{
|
||
USHORT uiTag = 0;
|
||
LPCDXTAG pTag = NULL;
|
||
LPCDXINDEX pCdx = pArea->lpIndexes;
|
||
|
||
if ( pFindTag )
|
||
{
|
||
while ( pCdx && ( pTag != pFindTag ) )
|
||
{
|
||
pTag = pCdx->TagList;
|
||
while ( pTag )
|
||
{
|
||
uiTag++;
|
||
if ( pTag == pFindTag )
|
||
break;
|
||
pTag = pTag->pNext;
|
||
}
|
||
pCdx = pCdx->pNext;
|
||
}
|
||
if ( !pTag )
|
||
uiTag = 0;
|
||
}
|
||
return uiTag;
|
||
}
|
||
|
||
/*
|
||
* find Tag in tag list
|
||
*/
|
||
static USHORT hb_cdxFindTag( CDXAREAP pArea, PHB_ITEM pItem )
|
||
{
|
||
USHORT uiTag = 0;
|
||
|
||
if ( pItem )
|
||
{
|
||
if ( HB_IS_NUMBER( pItem ) )
|
||
{
|
||
uiTag = hb_itemGetNI( pItem );
|
||
if ( ! hb_cdxGetTagByNumber(pArea, uiTag ) )
|
||
uiTag = 0;
|
||
}
|
||
else if ( HB_IS_STRING( pItem ) )
|
||
{
|
||
LPCDXTAG pTag;
|
||
LPCDXINDEX pIndex;
|
||
char szName[ CDX_MAXTAGNAMELEN + 1 ];
|
||
|
||
hb_strncpyUpperTrim( szName, pItem->item.asString.value,
|
||
HB_MIN( pItem->item.asString.length, CDX_MAXTAGNAMELEN) );
|
||
pIndex = pArea->lpIndexes;
|
||
pTag = NULL;
|
||
uiTag = 0;
|
||
while ( pIndex && !pTag)
|
||
{
|
||
pTag = pIndex->TagList;
|
||
while ( pTag )
|
||
{
|
||
uiTag++;
|
||
if ( !hb_stricmp( pTag->szName, szName ) )
|
||
break;
|
||
pTag = pTag->pNext;
|
||
}
|
||
pIndex = pIndex->pNext;
|
||
}
|
||
if ( !pTag )
|
||
uiTag = 0;
|
||
}
|
||
}
|
||
|
||
return uiTag;
|
||
}
|
||
|
||
/*
|
||
* get current active Tag
|
||
*/
|
||
static LPCDXTAG hb_cdxGetActiveTag( CDXAREAP pArea )
|
||
{
|
||
LPCDXTAG pTag;
|
||
|
||
if ( !pArea->uiTag )
|
||
return NULL;
|
||
pTag = hb_cdxGetTagByNumber( pArea, pArea->uiTag );
|
||
if ( !pTag )
|
||
pArea->uiTag = 0;
|
||
return pTag;
|
||
}
|
||
|
||
/*
|
||
* refresh CurKey value and set proper path from RootPage to LeafPage
|
||
* fUniq is used for forward skipunique
|
||
*/
|
||
static BOOL hb_cdxCurKeyRefresh( CDXAREAP pArea, LPCDXTAG pTag, BOOL fUniq )
|
||
{
|
||
if ( pArea->fEof || pArea->ulRecNo == 0 )
|
||
{
|
||
pTag->TagEOF = TRUE;
|
||
pTag->fRePos = FALSE;
|
||
pTag->CurKey->rec = 0;
|
||
return FALSE;
|
||
}
|
||
else if ( pTag->fRePos || pTag->CurKey->rec != pArea->ulRecNo )
|
||
{
|
||
if ( pTag->CurKey->rec == pArea->ulRecNo )
|
||
hb_cdxTagKeyFind( pTag, pTag->CurKey );
|
||
if ( pTag->CurKey->rec != pArea->ulRecNo )
|
||
{
|
||
LPCDXKEY pKey = hb_cdxKeyEval( NULL, pTag, TRUE );
|
||
hb_cdxTagKeyFind( pTag, pKey );
|
||
if ( fUniq && !pTag->TagEOF && pTag->CurKey->rec != pArea->ulRecNo )
|
||
{
|
||
memcpy( pTag->CurKey->val, pKey->val, pKey->len );
|
||
pTag->CurKey->rec = 0;
|
||
}
|
||
hb_cdxKeyFree( pKey );
|
||
}
|
||
return ( pTag->CurKey->rec != 0 && pTag->CurKey->rec == pArea->ulRecNo );
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* skip to next unique key
|
||
*/
|
||
static ERRCODE hb_cdxSkipUnique( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward )
|
||
{
|
||
ERRCODE retval;
|
||
BOOL fOut = FALSE;
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("hb_cdxSkipUnique(%p, %p, %i)", pArea, pTag, fForward));
|
||
|
||
if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE )
|
||
return FAILURE;
|
||
|
||
if ( ! pTag )
|
||
return SELF_SKIP( ( AREAP ) pArea, fForward ? 1 : -1 );
|
||
|
||
hb_cdxIndexLockRead( pTag->pIndex );
|
||
if ( !pArea->fEof )
|
||
{
|
||
if ( ! hb_cdxCurKeyRefresh( pArea, pTag, fForward ) )
|
||
{
|
||
if ( !fForward && pTag->TagEOF && !pArea->fEof )
|
||
fOut = TRUE;
|
||
}
|
||
}
|
||
if ( fForward )
|
||
{
|
||
if ( !pArea->fEof && !pTag->TagEOF )
|
||
{
|
||
hb_cdxTagKeyRead( pTag, NXTU_RECORD );
|
||
if ( !pTag->TagEOF )
|
||
{
|
||
if ( !hb_cdxTopScope( pTag ) )
|
||
hb_cdxTagKeyFind( pTag, pTag->topScopeKey );
|
||
if ( !hb_cdxBottomScope( pTag ) )
|
||
fOut = TRUE;
|
||
}
|
||
}
|
||
retval = SELF_GOTO( ( AREAP ) pArea, ( fOut || pArea->fEof || pTag->TagEOF )
|
||
? 0 : pTag->CurKey->rec );
|
||
}
|
||
else
|
||
{
|
||
if ( pArea->fEof )
|
||
{
|
||
retval = SELF_GOBOTTOM( ( AREAP ) pArea );
|
||
}
|
||
else
|
||
{
|
||
if ( !fOut && !pTag->TagBOF )
|
||
{
|
||
hb_cdxTagKeyRead( pTag, PRVU_RECORD );
|
||
if ( !pTag->TagBOF )
|
||
{
|
||
if ( !hb_cdxTopScope( pTag ) ||
|
||
!hb_cdxBottomScope( pTag ) )
|
||
fOut = TRUE;
|
||
}
|
||
}
|
||
if ( fOut || pTag->TagBOF )
|
||
{
|
||
retval = SELF_GOTOP( ( AREAP ) pArea );
|
||
pArea->fBof = TRUE;
|
||
}
|
||
else
|
||
{
|
||
retval = SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec );
|
||
}
|
||
}
|
||
}
|
||
hb_cdxIndexUnLockRead( pTag->pIndex );
|
||
|
||
/* Update Bof and Eof flags */
|
||
if( fForward )
|
||
pArea->fBof = FALSE;
|
||
else
|
||
pArea->fEof = FALSE;
|
||
|
||
return retval;
|
||
}
|
||
|
||
/*
|
||
* skip while code block doesn't return TRUE
|
||
*/
|
||
static BOOL hb_cdxDBOISkipEval( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward,
|
||
PHB_ITEM pEval )
|
||
{
|
||
BOOL fFound = FALSE;
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("hb_cdxSkipEval(%p, %p, %i, %p)", pArea, pTag, fForward, pEval));
|
||
|
||
if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE )
|
||
return FALSE;
|
||
|
||
if ( ! pTag || ! HB_IS_BLOCK( pEval ) )
|
||
{
|
||
if ( SELF_SKIP( ( AREAP ) pArea, fForward ? 1 : -1 ) == FAILURE )
|
||
return FALSE;
|
||
return fForward ? !pArea->fEof : !pArea->fBof;
|
||
}
|
||
|
||
hb_cdxIndexLockRead( pTag->pIndex );
|
||
if ( !pArea->fEof )
|
||
{
|
||
hb_cdxCurKeyRefresh( pArea, pTag, FALSE );
|
||
}
|
||
if ( fForward )
|
||
{
|
||
if ( !pTag->TagEOF && !pArea->fEof )
|
||
{
|
||
if ( !hb_cdxTopScope( pTag ) )
|
||
hb_cdxTagKeyFind( pTag, pTag->topScopeKey );
|
||
else
|
||
hb_cdxTagKeyRead( pTag, NEXT_RECORD );
|
||
|
||
while ( !pTag->TagEOF && hb_cdxBottomScope( pTag ) )
|
||
{
|
||
if ( SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec ) == FAILURE )
|
||
break;
|
||
fFound = hb_cdxEvalSeekCond( pTag, pEval );
|
||
if ( fFound )
|
||
break;
|
||
hb_cdxTagKeyRead( pTag, NEXT_RECORD );
|
||
}
|
||
}
|
||
if ( !fFound )
|
||
SELF_GOTO( ( AREAP ) pArea, 0 );
|
||
}
|
||
else
|
||
{
|
||
if ( pArea->fEof )
|
||
SELF_GOBOTTOM( ( AREAP ) pArea );
|
||
else if ( !pTag->TagBOF )
|
||
hb_cdxTagKeyRead( pTag, PREV_RECORD );
|
||
|
||
while ( !pTag->TagBOF && hb_cdxTopScope( pTag ) && hb_cdxBottomScope( pTag ) )
|
||
{
|
||
if ( SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec ) == FAILURE )
|
||
break;
|
||
fFound = hb_cdxEvalSeekCond( pTag, pEval );
|
||
if ( fFound )
|
||
break;
|
||
hb_cdxTagKeyRead( pTag, PREV_RECORD );
|
||
}
|
||
if ( !fFound )
|
||
{
|
||
SELF_GOTOP( ( AREAP ) pArea );
|
||
pArea->fBof = TRUE;
|
||
}
|
||
}
|
||
hb_cdxIndexUnLockRead( pTag->pIndex );
|
||
|
||
/* Update Bof and Eof flags */
|
||
if( fForward )
|
||
pArea->fBof = FALSE;
|
||
else
|
||
pArea->fEof = FALSE;
|
||
|
||
return fFound;
|
||
}
|
||
|
||
/*
|
||
* return number of keys in order
|
||
*/
|
||
static LONG hb_cdxDBOIKeyCount( CDXAREAP pArea, LPCDXTAG pTag, BOOL fFilters )
|
||
{
|
||
ULONG lKeyCount = 0;
|
||
|
||
/* TODO: what with deleted flag? */
|
||
if ( fFilters && ! pArea->dbfi.itmCobExpr )
|
||
fFilters = FALSE;
|
||
|
||
if ( fFilters )
|
||
{
|
||
PHB_ITEM pRecNo;
|
||
ULONG ulRec;
|
||
USHORT uiTag;
|
||
LPDBRELINFO lpdbRelations;
|
||
|
||
uiTag = pArea->uiTag;
|
||
pArea->uiTag = hb_cdxGetTagNumber( pArea, pTag );
|
||
/* remove relations when skiping: it's faster and resolve problem
|
||
* when child can repos on skip */
|
||
lpdbRelations = pArea->lpdbRelations;
|
||
pArea->lpdbRelations = NULL;
|
||
|
||
pRecNo = hb_itemPutNL( NULL, 0 );
|
||
SELF_RECNO( ( AREAP ) pArea, pRecNo );
|
||
ulRec = hb_itemGetNL( pRecNo );
|
||
hb_itemRelease( pRecNo );
|
||
|
||
SELF_GOTOP( ( AREAP ) pArea );
|
||
while ( !( ( AREAP ) pArea )->fEof )
|
||
{
|
||
lKeyCount++;
|
||
SELF_SKIP( ( AREAP ) pArea, 1 );
|
||
}
|
||
SELF_GOTO( ( AREAP ) pArea, ulRec );
|
||
/* restore relations and current order */
|
||
pArea->lpdbRelations = lpdbRelations;
|
||
pArea->uiTag = uiTag;
|
||
}
|
||
else if ( pTag )
|
||
{
|
||
LPCDXKEY pCurKey;
|
||
hb_cdxIndexLockRead( pTag->pIndex );
|
||
pCurKey = hb_cdxKeyCopy( NULL, pTag->CurKey );
|
||
|
||
if ( pTag->topScope || pTag->bottomScope || pTag->UsrUnique )
|
||
{
|
||
if ( pTag->topScope )
|
||
hb_cdxTagKeyFind( pTag, pTag->topScopeKey );
|
||
else
|
||
hb_cdxTagKeyRead( pTag, TOP_RECORD );
|
||
while ( !pTag->TagEOF && hb_cdxBottomScope( pTag ) )
|
||
{
|
||
lKeyCount++;
|
||
hb_cdxTagKeyRead( pTag, NEXT_RECORD );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
LPCDXPAGE pPage;
|
||
hb_cdxTagKeyRead( pTag, TOP_RECORD );
|
||
pPage = pTag->RootPage;
|
||
while ( pPage->Child )
|
||
pPage = pPage->Child;
|
||
lKeyCount = pPage->iKeys;
|
||
if ( pPage->Right != CDX_DUMMYNODE )
|
||
{
|
||
ULONG ulPage = pPage->Right;
|
||
pPage = hb_cdxPageNew( pTag, NULL, CDX_DUMMYNODE );
|
||
pPage->Page = ulPage;
|
||
while ( pPage->Page != CDX_DUMMYNODE )
|
||
{
|
||
hb_cdxPageLoad( pPage );
|
||
lKeyCount += pPage->iKeys;
|
||
pPage->Page = pPage->Right;
|
||
}
|
||
hb_cdxPageFree( pPage, TRUE );
|
||
}
|
||
}
|
||
pTag->fRePos = TRUE;
|
||
hb_cdxKeyCopy( pTag->CurKey, pCurKey );
|
||
hb_cdxKeyFree( pCurKey );
|
||
hb_cdxIndexUnLockRead( pTag->pIndex );
|
||
}
|
||
else /* no filter, no order */
|
||
{
|
||
SELF_RECCOUNT( ( AREAP ) pArea, &lKeyCount );
|
||
}
|
||
return lKeyCount;
|
||
}
|
||
|
||
/*
|
||
* return logical key position in order
|
||
*/
|
||
static LONG hb_cdxDBOIKeyNo( CDXAREAP pArea, LPCDXTAG pTag, BOOL fFilters )
|
||
{
|
||
ULONG lKeyNo = 0;
|
||
|
||
/* TODO: what with deleted flag? */
|
||
if ( fFilters && ! pArea->dbfi.itmCobExpr )
|
||
fFilters = 0;
|
||
|
||
if ( pArea->fEof )
|
||
lKeyNo = 0;
|
||
else if ( fFilters )
|
||
{
|
||
PHB_ITEM pRecNo;
|
||
ULONG ulRec;
|
||
USHORT uiTag;
|
||
LPDBRELINFO lpdbRelations;
|
||
|
||
uiTag = pArea->uiTag;
|
||
pArea->uiTag = hb_cdxGetTagNumber( pArea, pTag );
|
||
/* remove relations when skiping: it's faster and resolve problem
|
||
* when child can repos on skip */
|
||
lpdbRelations = pArea->lpdbRelations;
|
||
pArea->lpdbRelations = NULL;
|
||
|
||
pRecNo = hb_itemPutNL( NULL, 0 );
|
||
SELF_RECNO( ( AREAP ) pArea, pRecNo );
|
||
ulRec = hb_itemGetNL( pRecNo );
|
||
hb_itemRelease( pRecNo );
|
||
do
|
||
{
|
||
lKeyNo++;
|
||
SELF_SKIP( ( AREAP ) pArea, -1 );
|
||
} while ( !( ( AREAP ) pArea )->fBof );
|
||
SELF_GOTO( ( AREAP ) pArea, ulRec );
|
||
/* restore relations and current order */
|
||
pArea->lpdbRelations = lpdbRelations;
|
||
pArea->uiTag = uiTag;
|
||
}
|
||
else if ( pTag )
|
||
{
|
||
hb_cdxIndexLockRead( pTag->pIndex );
|
||
if ( hb_cdxCurKeyRefresh( pArea, pTag, FALSE ) )
|
||
{
|
||
if ( pTag->topScope || pTag->bottomScope || pTag->UsrUnique )
|
||
{
|
||
if ( hb_cdxBottomScope( pTag ) )
|
||
{
|
||
LPCDXKEY pCurKey = hb_cdxKeyCopy( NULL, pTag->CurKey );
|
||
while ( !pTag->TagBOF && !pTag->TagEOF && hb_cdxTopScope( pTag ) )
|
||
{
|
||
lKeyNo++;
|
||
hb_cdxTagKeyRead( pTag, PREV_RECORD );
|
||
}
|
||
pTag->fRePos = TRUE;
|
||
hb_cdxKeyCopy( pTag->CurKey, pCurKey );
|
||
hb_cdxKeyFree( pCurKey );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
LPCDXPAGE pPage = pTag->RootPage;
|
||
while ( pPage->Child )
|
||
pPage = pPage->Child;
|
||
if ( pTag->UsrAscend )
|
||
{
|
||
lKeyNo = pPage->iCurKey + 1;
|
||
if ( pPage->Left != CDX_DUMMYNODE )
|
||
{
|
||
ULONG ulPage = pPage->Left;
|
||
pPage = hb_cdxPageNew( pTag, NULL, CDX_DUMMYNODE );
|
||
pPage->Page = ulPage;
|
||
while ( pPage->Page != CDX_DUMMYNODE )
|
||
{
|
||
hb_cdxPageLoad( pPage );
|
||
lKeyNo += pPage->iKeys;
|
||
pPage->Page = pPage->Left;
|
||
}
|
||
hb_cdxPageFree( pPage, TRUE );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
lKeyNo = pPage->iKeys - pPage->iCurKey;
|
||
if ( pPage->Right != CDX_DUMMYNODE )
|
||
{
|
||
ULONG ulPage = pPage->Right;
|
||
pPage = hb_cdxPageNew( pTag, NULL, CDX_DUMMYNODE );
|
||
pPage->Page = ulPage;
|
||
while ( pPage->Page != CDX_DUMMYNODE )
|
||
{
|
||
hb_cdxPageLoad( pPage );
|
||
lKeyNo += pPage->iKeys;
|
||
pPage->Page = pPage->Right;
|
||
}
|
||
hb_cdxPageFree( pPage, TRUE );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
hb_cdxIndexUnLockRead( pTag->pIndex );
|
||
}
|
||
else
|
||
{
|
||
PHB_ITEM pRecNo;
|
||
pRecNo = hb_itemPutNL( NULL, 0 );
|
||
SELF_RECNO( ( AREAP ) pArea, pRecNo );
|
||
lKeyNo = hb_itemGetNL( pRecNo );
|
||
hb_itemRelease( pRecNo );
|
||
}
|
||
return lKeyNo;
|
||
}
|
||
|
||
/*
|
||
* DBOI_KEYGOTO goto specific logical record in the index file
|
||
*/
|
||
static ERRCODE hb_cdxDBOIKeyGoto( CDXAREAP pArea, LPCDXTAG pTag, ULONG ulKeyNo, BOOL fFilters )
|
||
{
|
||
ERRCODE retval;
|
||
|
||
/* TODO: what with deleted flag? */
|
||
if ( fFilters && ! pArea->dbfi.itmCobExpr )
|
||
fFilters = 0;
|
||
|
||
if ( ulKeyNo == 0 )
|
||
retval = SELF_GOTO( ( AREAP ) pArea, 0 );
|
||
else if ( fFilters )
|
||
{
|
||
USHORT uiTag = pArea->uiTag;
|
||
pArea->uiTag = hb_cdxGetTagNumber( pArea, pTag );
|
||
retval = SELF_GOTOP( ( AREAP ) pArea );
|
||
while ( !pArea->fEof && ulKeyNo-- )
|
||
retval = SELF_SKIP( ( AREAP ) pArea, 1 );
|
||
pArea->uiTag = uiTag;
|
||
}
|
||
else if ( pTag )
|
||
{
|
||
hb_cdxIndexLockRead( pTag->pIndex );
|
||
if ( pTag->topScope || pTag->bottomScope || pTag->UsrUnique )
|
||
{
|
||
if ( pTag->topScope )
|
||
hb_cdxTagKeyFind( pTag, pTag->topScopeKey );
|
||
else
|
||
hb_cdxTagKeyRead( pTag, TOP_RECORD );
|
||
while ( !pTag->TagBOF && !pTag->TagEOF && hb_cdxBottomScope( pTag ) &&
|
||
--ulKeyNo )
|
||
hb_cdxTagKeyRead( pTag, NEXT_RECORD );
|
||
}
|
||
else
|
||
{
|
||
LPCDXPAGE pPage, pOwnerPage = NULL;
|
||
ULONG ulNextPg;
|
||
hb_cdxTagKeyRead( pTag, TOP_RECORD );
|
||
pPage = pTag->RootPage;
|
||
while ( pPage->Child )
|
||
{
|
||
pOwnerPage = pPage;
|
||
pPage = pPage->Child;
|
||
}
|
||
while ( (ULONG) pPage->iKeys < ulKeyNo && pOwnerPage &&
|
||
( ulNextPg = pTag->UsrAscend ?
|
||
pPage->Right : pPage->Left ) != CDX_DUMMYNODE )
|
||
{
|
||
ulKeyNo -= pPage->iKeys;
|
||
pOwnerPage->Child = hb_cdxPageNew( pPage->TagParent, pPage->Owner, ulNextPg );
|
||
hb_cdxPageFree( pPage, FALSE );
|
||
pPage = pOwnerPage->Child;
|
||
}
|
||
if ( (ULONG) pPage->iKeys >= ulKeyNo )
|
||
{
|
||
pPage->iCurKey = pTag->UsrAscend ? ( SHORT ) ulKeyNo - 1 : pPage->iKeys - ( SHORT ) ulKeyNo;
|
||
hb_cdxSetCurKey( pPage );
|
||
}
|
||
else
|
||
pTag->CurKey->rec = 0;
|
||
}
|
||
hb_cdxIndexUnLockRead( pTag->pIndex );
|
||
retval = SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec );
|
||
}
|
||
else
|
||
{
|
||
retval = SELF_GOTO( ( AREAP ) pArea, ulKeyNo );
|
||
}
|
||
|
||
return retval;
|
||
}
|
||
|
||
|
||
/*
|
||
* -- DBFCDX METHODS --
|
||
*/
|
||
|
||
/* ( DBENTRYP_BP ) hb_cdxBof : NULL */
|
||
/* ( DBENTRYP_BP ) hb_cdxEof : NULL */
|
||
/* ( DBENTRYP_BP ) hb_cdxFound : NULL */
|
||
|
||
/* ( DBENTRYP_V ) hb_cdxGoBottom */
|
||
static ERRCODE hb_cdxGoBottom( CDXAREAP pArea )
|
||
{
|
||
LPCDXTAG pTag;
|
||
ERRCODE retval;
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("cdxGoBottom(%p)", pArea));
|
||
|
||
if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE )
|
||
return FAILURE;
|
||
|
||
pTag = hb_cdxGetActiveTag( pArea );
|
||
if ( ! pTag )
|
||
return SUPER_GOBOTTOM( ( AREAP ) pArea );
|
||
|
||
hb_cdxIndexLockRead( pTag->pIndex );
|
||
if ( pTag->bottomScope )
|
||
hb_cdxTagKeyFind( pTag, pTag->bottomScopeKey );
|
||
else
|
||
hb_cdxTagKeyRead( pTag, BTTM_RECORD );
|
||
if ( pTag->CurKey->rec != 0 && ! hb_cdxTopScope( pTag ) )
|
||
pTag->CurKey->rec = 0;
|
||
|
||
pArea->fTop = FALSE;
|
||
pArea->fBottom = TRUE;
|
||
|
||
retval = SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec );
|
||
if ( retval != FAILURE && !pArea->fEof )
|
||
retval = SELF_SKIPFILTER( ( AREAP ) pArea, -1 );
|
||
hb_cdxIndexUnLockRead( pTag->pIndex );
|
||
return retval;
|
||
}
|
||
|
||
/* ( DBENTRYP_UL ) hb_cdxGoTo : NULL */
|
||
/* ( DBENTRYP_I ) hb_cdxGoToId : NULL */
|
||
|
||
/* ( DBENTRYP_V ) hb_cdxGoTop */
|
||
static ERRCODE hb_cdxGoTop( CDXAREAP pArea )
|
||
{
|
||
LPCDXTAG pTag;
|
||
ERRCODE retval;
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("cdxGoTop(%p)", pArea));
|
||
|
||
if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE )
|
||
return FAILURE;
|
||
|
||
pTag = hb_cdxGetActiveTag( pArea );
|
||
if ( ! pTag )
|
||
return SUPER_GOTOP( ( AREAP ) pArea );
|
||
|
||
hb_cdxIndexLockRead( pTag->pIndex );
|
||
if ( pTag->topScope )
|
||
hb_cdxTagKeyFind( pTag, pTag->topScopeKey );
|
||
else
|
||
hb_cdxTagKeyRead( pTag, TOP_RECORD );
|
||
if ( pTag->CurKey->rec != 0 && ! hb_cdxBottomScope( pTag ) )
|
||
pTag->CurKey->rec = 0;
|
||
|
||
pArea->fTop = TRUE;
|
||
pArea->fBottom = FALSE;
|
||
|
||
retval = SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec );
|
||
if ( retval != FAILURE && !pArea->fEof )
|
||
retval = SELF_SKIPFILTER( ( AREAP ) pArea, 1 );
|
||
hb_cdxIndexUnLockRead( pTag->pIndex );
|
||
return retval;
|
||
}
|
||
|
||
/* ( DBENTRYP_BIB ) hb_cdxSeek */
|
||
static ERRCODE hb_cdxSeek( CDXAREAP pArea, BOOL fSoftSeek, PHB_ITEM pKeyItm, BOOL fFindLast )
|
||
{
|
||
LPCDXTAG pTag;
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("cdxSeek(%p, %d, %p, %d)", pArea, fSoftSeek, pKeyItm, fFindLast));
|
||
|
||
if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE )
|
||
return FAILURE;
|
||
|
||
pTag = hb_cdxGetActiveTag( pArea );
|
||
|
||
if ( ! pTag )
|
||
{
|
||
hb_cdxErrorRT( pArea, EG_NOORDER, 1201, NULL, EF_CANDEFAULT );
|
||
return FAILURE;
|
||
}
|
||
else
|
||
{
|
||
LPCDXKEY pKey;
|
||
ERRCODE retval = SUCCESS;
|
||
BOOL fEOF = FALSE;
|
||
ULONG ulRec;
|
||
|
||
pArea->fTop = pArea->fBottom = FALSE;
|
||
pArea->fEof = FALSE;
|
||
|
||
if ( !pTag->UsrAscend )
|
||
fFindLast = !fFindLast;
|
||
|
||
/* TODO: runtime error if valtype(pKeyItm) != pTag->Type */
|
||
pKey = hb_cdxKeyPutItem( NULL, pKeyItm, fFindLast ? CDX_MAX_REC_NUM : CDX_IGNORE_REC_NUM, pTag, TRUE, FALSE );
|
||
|
||
hb_cdxIndexLockRead( pTag->pIndex );
|
||
ulRec = hb_cdxTagKeyFind( pTag, pKey );
|
||
if ( ( ulRec == 0 && ! fSoftSeek ) || pTag->TagEOF )
|
||
fEOF = TRUE;
|
||
else if ( fSoftSeek )
|
||
{
|
||
if ( pTag->UsrAscend )
|
||
{
|
||
if ( ! hb_cdxBottomScope( pTag ) )
|
||
fEOF = TRUE;
|
||
else if ( ! hb_cdxTopScope( pTag ) )
|
||
hb_cdxTagKeyFind( pTag, pTag->topScopeKey );
|
||
}
|
||
else
|
||
{
|
||
if ( ! hb_cdxTopScope( pTag ) )
|
||
fEOF = TRUE;
|
||
else if ( ! hb_cdxBottomScope( pTag ) )
|
||
hb_cdxTagKeyFind( pTag, pTag->bottomScopeKey );
|
||
}
|
||
if ( pTag->CurKey->rec == 0 )
|
||
fEOF = TRUE;
|
||
}
|
||
hb_cdxIndexUnLockRead( pTag->pIndex );
|
||
if ( !fEOF )
|
||
{
|
||
retval = SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec );
|
||
if ( retval != FAILURE && !pArea->fEof )
|
||
{
|
||
retval = SELF_SKIPFILTER( ( AREAP ) pArea, fFindLast ? -1 : 1 );
|
||
if ( retval != FAILURE && ulRec && ! pArea->fEof )
|
||
{
|
||
pArea->fFound = ( ulRec == pArea->ulRecNo ||
|
||
hb_cdxValCompare( pTag, pKey->val, pKey->len,
|
||
pTag->CurKey->val, pTag->CurKey->len, FALSE ) == 0 );
|
||
if ( ! pArea->fFound && ! fSoftSeek )
|
||
fEOF = TRUE;
|
||
}
|
||
}
|
||
}
|
||
if ( retval != FAILURE && ! pArea->fEof &&
|
||
( fEOF || ! hb_cdxTopScope( pTag ) ||
|
||
! hb_cdxBottomScope( pTag ) ) )
|
||
{
|
||
retval = SELF_GOTO( ( AREAP ) pArea, 0 );
|
||
}
|
||
pArea->fBof = FALSE;
|
||
hb_cdxKeyFree( pKey );
|
||
return retval;
|
||
}
|
||
}
|
||
|
||
/* ( DBENTRYP_L ) hb_cdxSkip : NULL */
|
||
/* ( DBENTRYP_L ) hb_cdxSkipFilter : NULL */
|
||
|
||
/* ( DBENTRYP_L ) hb_cdxSkipRaw */
|
||
static ERRCODE hb_cdxSkipRaw( CDXAREAP pArea, LONG lToSkip )
|
||
{
|
||
LPCDXTAG pTag;
|
||
ERRCODE retval;
|
||
BOOL fOut = FALSE;
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("cdxSkipRaw(%p, %ld)", pArea, lToSkip));
|
||
|
||
if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE )
|
||
return FAILURE;
|
||
|
||
pTag = hb_cdxGetActiveTag( pArea );
|
||
|
||
if ( ! pTag || lToSkip == 0 )
|
||
return SUPER_SKIPRAW( ( AREAP ) pArea, lToSkip );
|
||
|
||
hb_cdxIndexLockRead( pTag->pIndex );
|
||
if ( !pArea->fEof )
|
||
{
|
||
if ( ! hb_cdxCurKeyRefresh( pArea, pTag, FALSE ) )
|
||
{
|
||
if ( lToSkip > 0 )
|
||
{
|
||
if ( pTag->TagEOF )
|
||
fOut = TRUE;
|
||
else
|
||
lToSkip--;
|
||
}
|
||
else if ( pTag->TagEOF && !pArea->fEof )
|
||
fOut = TRUE;
|
||
}
|
||
}
|
||
if ( lToSkip >= 0 )
|
||
{
|
||
if ( !pArea->fEof && !fOut )
|
||
{
|
||
while ( !pTag->TagEOF && lToSkip-- > 0 )
|
||
{
|
||
hb_cdxTagKeyRead( pTag, NEXT_RECORD );
|
||
if ( !pTag->TagEOF )
|
||
{
|
||
if ( !hb_cdxTopScope( pTag ) )
|
||
hb_cdxTagKeyFind( pTag, pTag->topScopeKey );
|
||
else if ( !hb_cdxBottomScope( pTag ) )
|
||
{
|
||
fOut = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
retval = SELF_GOTO( ( AREAP ) pArea, ( pArea->fEof || pTag->TagEOF || fOut )
|
||
? 0 : pTag->CurKey->rec );
|
||
}
|
||
else /* if ( lToSkip < 0 ) */
|
||
{
|
||
if ( pArea->fEof )
|
||
{
|
||
if ( pTag->bottomScope )
|
||
hb_cdxTagKeyFind( pTag, pTag->bottomScopeKey );
|
||
else
|
||
hb_cdxTagKeyRead( pTag, BTTM_RECORD );
|
||
if ( pTag->CurKey->rec == 0 || ! hb_cdxTopScope( pTag ) )
|
||
fOut = TRUE;
|
||
lToSkip++;
|
||
}
|
||
while ( !fOut && !pTag->TagBOF && lToSkip++ < 0 )
|
||
{
|
||
hb_cdxTagKeyRead( pTag, PREV_RECORD );
|
||
if ( pTag->TagBOF || !hb_cdxTopScope( pTag ) || !hb_cdxBottomScope( pTag ) )
|
||
{
|
||
fOut = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
if ( fOut || pTag->TagBOF )
|
||
{
|
||
if ( pTag->topScope )
|
||
hb_cdxTagKeyFind( pTag, pTag->topScopeKey );
|
||
else
|
||
hb_cdxTagKeyRead( pTag, TOP_RECORD );
|
||
if ( pTag->CurKey->rec != 0 && ! hb_cdxBottomScope( pTag ) )
|
||
pTag->CurKey->rec = 0;
|
||
fOut = TRUE;
|
||
}
|
||
retval = SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec );
|
||
pArea->fBof = fOut;
|
||
}
|
||
hb_cdxIndexUnLockRead( pTag->pIndex );
|
||
return retval;
|
||
}
|
||
|
||
/* ( DBENTRYP_VF ) hb_cdxAddField : NULL */
|
||
/* ( DBENTRYP_B ) hb_cdxAppend : NULL */
|
||
/* ( DBENTRYP_I ) hb_cdxCreateFields : NULL */
|
||
/* ( DBENTRYP_V ) hb_cdxDeleteRec : NULL */
|
||
/* ( DBENTRYP_BP ) hb_cdxDeleted : NULL */
|
||
/* ( DBENTRYP_SP ) hb_cdxFieldCount : NULL */
|
||
/* ( DBENTRYP_VF ) hb_cdxFieldDisplay : NULL */
|
||
/* ( DBENTRYP_SSI ) hb_cdxFieldInfo : NULL */
|
||
/* ( DBENTRYP_SVP ) hb_cdxFieldName : NULL */
|
||
|
||
/* ( DBENTRYP_V ) hb_cdxFlush : NULL */
|
||
/*
|
||
* Flush _system_ buffers to disk
|
||
*/
|
||
static ERRCODE hb_cdxFlush( CDXAREAP pArea )
|
||
{
|
||
LPCDXINDEX pIndex;
|
||
ERRCODE uiError;
|
||
|
||
uiError = SUPER_FLUSH( ( AREAP ) pArea );
|
||
|
||
pIndex = pArea->lpIndexes;
|
||
while ( pIndex )
|
||
{
|
||
if ( pIndex->hFile != FS_ERROR )
|
||
hb_fsCommit( pIndex->hFile );
|
||
pIndex = pIndex->pNext;
|
||
}
|
||
|
||
return uiError;
|
||
}
|
||
|
||
/* ( DBENTRYP_PP ) hb_cdxGetRec : NULL */
|
||
/* ( DBENTRYP_SI ) hb_cdxGetValue : NULL */
|
||
/* ( DBENTRYP_SVL ) hb_cdxGetVarLen : NULL */
|
||
|
||
/* ( DBENTRYP_V ) hb_cdxGoCold */
|
||
/*
|
||
* Perform a write of WorkArea memory to the data store.
|
||
*/
|
||
static ERRCODE hb_cdxGoCold( CDXAREAP pArea )
|
||
{
|
||
BOOL fRecordChanged = pArea->fRecordChanged;
|
||
BOOL fAppend = pArea->fAppend;
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("hb_cdxGoCold(%p)", pArea));
|
||
|
||
if ( SUPER_GOCOLD( ( AREAP ) pArea ) == FAILURE )
|
||
return FAILURE;
|
||
|
||
if ( ( fRecordChanged || pArea->fCdxAppend ) && pArea->lpIndexes )
|
||
{
|
||
LPCDXTAG pTag = pArea->lpIndexes->TagList;
|
||
LPCDXKEY pKey = NULL;
|
||
BOOL fAdd, fDel, fLck = FALSE;
|
||
|
||
if ( pArea->fShared )
|
||
{
|
||
if ( fAppend )
|
||
{
|
||
if ( pArea->fCdxAppend )
|
||
hb_cdxErrInternal( "hb_cdxGoCold: multiple appending without GOCOLD." );
|
||
pArea->fCdxAppend = TRUE;
|
||
return SUCCESS;
|
||
}
|
||
else
|
||
{
|
||
fAppend = pArea->fCdxAppend;
|
||
pArea->fCdxAppend = FALSE;
|
||
}
|
||
}
|
||
/* TODO:
|
||
* There is possible race condition here but not very dangerous.
|
||
* To avoid it we should Lock all index file before SUPER_GOCOLD
|
||
* but it makes other problem if two stations open the database index
|
||
* files in a differ order then they can block each other.
|
||
* Without changes in locking scheme we can do only one thing which
|
||
* is enough if there is only one index file: lock first index only
|
||
* before SUPER_GOCOLD
|
||
* Druzus, 05 Oct 2003 10:27:52 CEST
|
||
*/
|
||
|
||
while ( pTag )
|
||
{
|
||
if ( !pTag->Custom )
|
||
{
|
||
pKey = hb_cdxKeyEval( pKey, pTag, TRUE );
|
||
if ( pTag->pForItem != NULL )
|
||
fAdd = hb_cdxEvalCond ( pArea, pTag->pForItem, TRUE );
|
||
else
|
||
fAdd = TRUE;
|
||
|
||
if ( fAppend )
|
||
fDel = FALSE;
|
||
else
|
||
{
|
||
if ( hb_cdxValCompare( pTag, pKey->val, pKey->len,
|
||
pTag->HotKey->val, pTag->HotKey->len, TRUE ) == 0 )
|
||
{
|
||
fDel = !fAdd && pTag->HotFor;
|
||
fAdd = fAdd && !pTag->HotFor;
|
||
}
|
||
else
|
||
{
|
||
fDel = pTag->HotFor;
|
||
}
|
||
}
|
||
if ( fDel || fAdd )
|
||
{
|
||
if ( !fLck )
|
||
{
|
||
hb_cdxIndexLockWrite( pTag->pIndex );
|
||
fLck = TRUE;
|
||
}
|
||
if ( fDel && hb_cdxTagKeyFind( pTag, pTag->HotKey ) > 0 )
|
||
hb_cdxPageKeyDelete( pTag->RootPage );
|
||
if ( fAdd )
|
||
hb_cdxTagKeyAdd( pTag, pKey );
|
||
}
|
||
#if 0
|
||
if ( pTag->HotKey )
|
||
{
|
||
hb_cdxKeyFree( pTag->HotKey );
|
||
pTag->HotKey = NULL;
|
||
}
|
||
#endif
|
||
}
|
||
if ( pTag->pNext )
|
||
pTag = pTag->pNext;
|
||
else
|
||
{
|
||
if ( fLck )
|
||
{
|
||
hb_cdxIndexUnLockWrite( pTag->pIndex );
|
||
fLck = FALSE;
|
||
}
|
||
if ( pTag->pIndex->pNext )
|
||
pTag = pTag->pIndex->pNext->TagList;
|
||
else
|
||
pTag = NULL;
|
||
}
|
||
}
|
||
if ( pKey )
|
||
hb_cdxKeyFree( pKey );
|
||
}
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
/* ( DBENTRYP_V ) hb_cdxGoHot */
|
||
/*
|
||
* Mark the WorkArea data buffer as hot.
|
||
*/
|
||
static ERRCODE hb_cdxGoHot( CDXAREAP pArea )
|
||
{
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("hb_cdxGoHot(%p)", pArea));
|
||
|
||
if ( pArea->fRecordChanged )
|
||
hb_cdxErrInternal( "hb_cdxGoHot: multiple marking buffer as hot." );
|
||
|
||
if ( SUPER_GOHOT( ( AREAP ) pArea ) == FAILURE )
|
||
return FAILURE;
|
||
|
||
if ( pArea->lpIndexes && !pArea->fCdxAppend )
|
||
{
|
||
LPCDXTAG pTag = pArea->lpIndexes->TagList;
|
||
while ( pTag )
|
||
{
|
||
if ( !pTag->Custom )
|
||
{
|
||
pTag->HotKey = hb_cdxKeyEval( pTag->HotKey, pTag, TRUE );
|
||
pTag->HotFor = pTag->pForItem == NULL || hb_cdxEvalCond( pArea, pTag->pForItem, TRUE );
|
||
}
|
||
|
||
if ( pTag->pNext )
|
||
pTag = pTag->pNext;
|
||
else
|
||
{
|
||
if ( pTag->pIndex->pNext )
|
||
pTag = pTag->pIndex->pNext->TagList;
|
||
else
|
||
pTag = NULL;
|
||
}
|
||
}
|
||
}
|
||
return SUCCESS;
|
||
}
|
||
|
||
/* ( DBENTRYP_P ) hb_cdxPutRec : NULL */
|
||
/* ( DBENTRYP_SI ) hb_cdxPutValue : NULL */
|
||
/* ( DBENTRYP_V ) hb_cdxRecall : NULL */
|
||
/* ( DBENTRYP_ULP ) hb_cdxRecCount : NULL */
|
||
/* ( DBENTRYP_ISI ) hb_cdxRecInfo : NULL */
|
||
/* ( DBENTRYP_I ) hb_cdxRecNo : NULL */
|
||
/* ( DBENTRYP_S ) hb_cdxSetFieldExtent : NULL */
|
||
/* ( DBENTRYP_P ) hb_cdxAlias : NULL */
|
||
|
||
/* ( DBENTRYP_V ) hb_cdxClose */
|
||
/*
|
||
* Close the table in the WorkArea.
|
||
*/
|
||
static ERRCODE hb_cdxClose( CDXAREAP pArea )
|
||
{
|
||
HB_TRACE(HB_TR_DEBUG, ("hb_cdxClose(%p)", pArea));
|
||
|
||
if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE )
|
||
return FAILURE;
|
||
|
||
hb_cdxOrdListClear( pArea, TRUE, NULL );
|
||
if ( pArea->bCdxSortTab )
|
||
{
|
||
hb_xfree( pArea->bCdxSortTab );
|
||
pArea->bCdxSortTab = NULL;
|
||
}
|
||
#ifdef HB_CDX_DBGTIME
|
||
printf( "\r\ncdxTimeIntBld=%f, cdxTimeExtBld=%f, cdxTimeBld=%f\r\n"
|
||
"cdxTimeGetKey=%f, cdxTimeFreeKey=%f\r\n"
|
||
"cdxTimeExtBlc=%f, cdxTimeIntBlc=%f\r\n"
|
||
"cdxTimeTotal=%f\r\n",
|
||
(double) cdxTimeIntBld / 1000000, (double) cdxTimeExtBld / 1000000,
|
||
(double) ( cdxTimeIntBld + cdxTimeExtBld ) / 1000000,
|
||
(double) cdxTimeGetKey / 1000000, (double) cdxTimeFreeKey / 1000000,
|
||
(double) cdxTimeIntBlc / 1000000, (double) cdxTimeExtBlc / 1000000,
|
||
(double) ( cdxTimeIntBld + cdxTimeExtBld +
|
||
cdxTimeGetKey + cdxTimeFreeKey +
|
||
cdxTimeExtBlc + cdxTimeIntBlc ) / 1000000 );
|
||
fflush(stdout);
|
||
cdxTimeIntBld = cdxTimeExtBld = 0;
|
||
#endif
|
||
#ifdef HB_CDX_DBGUPDT
|
||
printf( "\r\n#reads=%ld, #writes=%ld, stacksize=%d\r\n", cdxReadNO, cdxWriteNO, cdxStackSize );
|
||
fflush(stdout);
|
||
cdxReadNO = cdxWriteNO = 0;
|
||
#endif
|
||
|
||
return SUPER_CLOSE( ( AREAP ) pArea );
|
||
}
|
||
|
||
/* ( DBENTRYP_VP ) hb_cdxCreate : NULL */
|
||
/* ( DBENTRYP_SI ) hb_cdxInfo : NULL */
|
||
/* ( DBENTRYP_V ) hb_cdxNewArea : NULL */
|
||
|
||
/* ( DBENTRYP_VP ) hb_cdxOpen */
|
||
/*
|
||
* Open a data store in the WorkArea.
|
||
*/
|
||
static ERRCODE hb_cdxOpen( CDXAREAP pArea, LPDBOPENINFO pOpenInfo )
|
||
{
|
||
HB_TRACE(HB_TR_DEBUG, ("hb_cdxOpen(%p, %p)", pArea, pOpenInfo));
|
||
|
||
if ( !pArea->bLockType )
|
||
{
|
||
if ( hb_set.HB_SET_DBFLOCKSCHEME )
|
||
pArea->bLockType = hb_set.HB_SET_DBFLOCKSCHEME;
|
||
else
|
||
pArea->bLockType = HB_SET_DBFLOCK_VFP;
|
||
}
|
||
if ( SUPER_OPEN( ( AREAP ) pArea, pOpenInfo ) == FAILURE )
|
||
{
|
||
return FAILURE;
|
||
}
|
||
|
||
/* If SET_AUTOPEN open index */
|
||
if ( pArea->fHasTags && hb_set.HB_SET_AUTOPEN )
|
||
{
|
||
char * szFileName;
|
||
BYTE szSpFile[ _POSIX_PATH_MAX + 3 + 10 ];
|
||
PHB_FNAME pFileName;
|
||
DBORDERINFO pOrderInfo;
|
||
|
||
pFileName = hb_fsFNameSplit( pArea->szDataFileName );
|
||
szFileName = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 3 );
|
||
szFileName[ 0 ] = '\0';
|
||
if ( pFileName->szPath )
|
||
strcpy( szFileName, pFileName->szPath );
|
||
strncat( szFileName, pFileName->szName, _POSIX_PATH_MAX - strlen( szFileName ) );
|
||
pOrderInfo.itmResult = hb_itemPutC( NULL, "" );
|
||
SELF_ORDINFO( ( AREAP ) pArea, DBOI_BAGEXT, &pOrderInfo );
|
||
strncat( szFileName, pOrderInfo.itmResult->item.asString.value, _POSIX_PATH_MAX - strlen( szFileName ) );
|
||
hb_itemRelease( pOrderInfo.itmResult );
|
||
hb_xfree( pFileName );
|
||
|
||
if ( hb_spFile( ( BYTE * ) szFileName, szSpFile ) )
|
||
{
|
||
pOrderInfo.itmResult = hb_itemPutNI( NULL, 0 );
|
||
pOrderInfo.atomBagName = hb_itemPutC( NULL, (char *) szSpFile );
|
||
pOrderInfo.itmOrder = NULL;
|
||
SELF_ORDLSTADD( ( AREAP ) pArea, &pOrderInfo );
|
||
pOrderInfo.itmOrder = hb_itemPutNI( NULL, hb_set.HB_SET_AUTORDER );
|
||
SELF_ORDLSTFOCUS( ( AREAP ) pArea, &pOrderInfo );
|
||
hb_itemRelease( pOrderInfo.atomBagName );
|
||
hb_itemRelease( pOrderInfo.itmOrder );
|
||
hb_itemRelease( pOrderInfo.itmResult );
|
||
|
||
SELF_GOTOP( ( AREAP ) pArea );
|
||
}
|
||
hb_xfree( szFileName );
|
||
}
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
/* ( DBENTRYP_V ) hb_cdxRelease : NULL */
|
||
|
||
/* ( DBENTRYP_SP ) hb_cdxStructSize */
|
||
/*
|
||
* Retrieve the size of the WorkArea structure.
|
||
*/
|
||
static ERRCODE hb_cdxStructSize( CDXAREAP pArea, USHORT * uiSize )
|
||
{
|
||
HB_TRACE(HB_TR_DEBUG, ("hb_cdxStrucSize(%p, %p)", pArea, uiSize));
|
||
HB_SYMBOL_UNUSED( pArea );
|
||
|
||
* uiSize = sizeof( CDXAREA );
|
||
return SUCCESS;
|
||
}
|
||
|
||
/* ( DBENTRYP_P ) hb_cdxSysName */
|
||
/*
|
||
* Obtain the name of replaceable database driver (RDD) subsystem.
|
||
*/
|
||
static ERRCODE hb_cdxSysName( CDXAREAP pArea, BYTE * pBuffer )
|
||
{
|
||
HB_TRACE(HB_TR_DEBUG, ("hb_cdxSysName(%p, %p)", pArea, pBuffer));
|
||
HB_SYMBOL_UNUSED( pArea );
|
||
|
||
strncpy( ( char * ) pBuffer, "DBFCDX", 7 /* HARBOUR_MAX_RDD_DRIVERNAME_LENGTH */ );
|
||
return SUCCESS;
|
||
}
|
||
|
||
/* ( DBENTRYP_VEI ) hb_cdxEval : NULL */
|
||
|
||
/* ( DBENTRYP_V ) hb_cdxPack */
|
||
static ERRCODE hb_cdxPack( CDXAREAP pArea )
|
||
{
|
||
HB_TRACE(HB_TR_DEBUG, ("nb_cdxPack(%p)", pArea ));
|
||
|
||
if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE )
|
||
return FAILURE;
|
||
|
||
if ( SUPER_PACK( ( AREAP ) pArea ) == SUCCESS )
|
||
{
|
||
return hb_cdxOrderListRebuild( pArea );
|
||
}
|
||
else
|
||
return FAILURE;
|
||
}
|
||
|
||
/* ( DBENTRYP_LSP ) hb_cdxPackRec : NULL */
|
||
/* ( DBENTRYP_VS ) hb_cdxSort : NULL */
|
||
/* ( DBENTRYP_VT ) hb_cdxTrans : NULL */
|
||
/* ( DBENTRYP_VT ) hb_cdxTransRec : NULL */
|
||
|
||
/* ( DBENTRYP_V ) hb_cdxZap */
|
||
static ERRCODE hb_cdxZap ( CDXAREAP pArea )
|
||
{
|
||
HB_TRACE(HB_TR_DEBUG, ("nb_cdxZap(%p)", pArea ));
|
||
|
||
if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE )
|
||
return FAILURE;
|
||
|
||
hb_cdxOrderListRebuild( pArea );
|
||
if ( SUPER_ZAP( ( AREAP ) pArea ) == SUCCESS )
|
||
{
|
||
return hb_cdxOrderListRebuild( pArea );
|
||
}
|
||
else
|
||
return FAILURE;
|
||
}
|
||
|
||
/* ( DBENTRYP_VR ) hb_cdxChildEnd : NULL */
|
||
/* ( DBENTRYP_VR ) hb_cdxChildStart : NULL */
|
||
/* ( DBENTRYP_VR ) hb_cdxChildSync : NULL */
|
||
/* ( DBENTRYP_V ) hb_cdxSyncChildren : NULL */
|
||
/* ( DBENTRYP_V ) hb_cdxClearRel : NULL */
|
||
/* ( DBENTRYP_V ) hb_cdxForceRel : NULL */
|
||
/* ( DBENTRYP_SVP ) hb_cdxRelArea : NULL */
|
||
/* ( DBENTRYP_VR ) hb_cdxRelEval : NULL */
|
||
/* ( DBENTRYP_SVP ) hb_cdxRelText : NULL */
|
||
/* ( DBENTRYP_VR ) hb_cdxSetRel : NULL */
|
||
|
||
/* ( DBENTRYP_OI ) hb_cdxOrderListAdd */
|
||
static ERRCODE hb_cdxOrderListAdd( CDXAREAP pArea, LPDBORDERINFO pOrderInfo )
|
||
{
|
||
USHORT uiFlags;
|
||
FHANDLE hFile;
|
||
char * szBaseName, * szFileName, * szFileNameDbfPath = NULL;
|
||
BYTE szSpFile[ _POSIX_PATH_MAX + 3 + 10 ];
|
||
LPCDXINDEX pIndex, pIndexTmp;
|
||
BOOL bRetry;
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("cdxOrderListAdd(%p, %p)", pArea, pOrderInfo));
|
||
|
||
if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE )
|
||
return FAILURE;
|
||
|
||
szFileName = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 3 );
|
||
strcpy( szFileName, pOrderInfo->atomBagName->item.asString.value );
|
||
szFileName = ( char * ) hb_fileNameConv( szFileName ) ;
|
||
|
||
if ( strlen( szFileName ) == 0 )
|
||
{
|
||
hb_xfree( szFileName );
|
||
return FAILURE;
|
||
}
|
||
else
|
||
{
|
||
PHB_FNAME pFileName = hb_fsFNameSplit( szFileName );
|
||
|
||
if ( !pFileName->szExtension )
|
||
{
|
||
DBORDERINFO pExtInfo;
|
||
pExtInfo.itmResult = hb_itemPutC( NULL, "" );
|
||
SELF_ORDINFO( ( AREAP ) pArea, DBOI_BAGEXT, &pExtInfo );
|
||
strcat( szFileName, pExtInfo.itmResult->item.asString.value );
|
||
hb_itemRelease( pExtInfo.itmResult );
|
||
}
|
||
szBaseName = ( char * ) hb_xgrab( CDX_MAXTAGNAMELEN + 1 );
|
||
hb_strncpyUpper( szBaseName, pFileName->szName, CDX_MAXTAGNAMELEN );
|
||
if ( !pFileName->szPath )
|
||
{
|
||
hb_xfree( pFileName );
|
||
pFileName = hb_fsFNameSplit( pArea->szDataFileName );
|
||
if ( pFileName->szPath )
|
||
{
|
||
szFileNameDbfPath = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 3 );
|
||
strcpy( szFileNameDbfPath, pFileName->szPath );
|
||
strncat( szFileNameDbfPath, szFileName,
|
||
_POSIX_PATH_MAX - strlen( szFileNameDbfPath ) );
|
||
}
|
||
}
|
||
hb_xfree( pFileName );
|
||
}
|
||
|
||
if ( pArea->lpIndexes != NULL)
|
||
{
|
||
pIndexTmp = pArea->lpIndexes;
|
||
while ( pIndexTmp && ( strcmp( szBaseName, pIndexTmp->pCompound->szName ) != 0 ) )
|
||
pIndexTmp = pIndexTmp->pNext;
|
||
if ( pIndexTmp )
|
||
{
|
||
/*
|
||
* index already open, do nothing
|
||
* TODO: the full pathname should be compared when APIs are available
|
||
* ??? I'm not sure, it breaks upper lewel API if we have
|
||
* two Bags with the same name. But we can close the old bag
|
||
* and open the new one - 10/05/2003 Druzus
|
||
*/
|
||
if ( ! pArea->uiTag )
|
||
{
|
||
pArea->uiTag = hb_cdxGetTagNumber( pArea, pIndexTmp->TagList );
|
||
SELF_GOTOP( ( AREAP ) pArea );
|
||
}
|
||
if ( szFileNameDbfPath != NULL )
|
||
hb_xfree( szFileNameDbfPath );
|
||
hb_xfree( szFileName );
|
||
hb_xfree( szBaseName );
|
||
return FAILURE;
|
||
}
|
||
}
|
||
|
||
uiFlags = ( pArea->fReadonly ? FO_READ : FO_READWRITE ) |
|
||
( pArea->fShared ? FO_DENYNONE : FO_EXCLUSIVE );
|
||
do
|
||
{
|
||
hFile = FS_ERROR;
|
||
if ( szFileNameDbfPath &&
|
||
hb_spFile( ( BYTE * ) szFileNameDbfPath, szSpFile ) )
|
||
hFile = hb_spOpen( szSpFile, uiFlags );
|
||
else if ( hb_spFile( ( BYTE * ) szFileName, szSpFile ) )
|
||
hFile = hb_spOpen( szSpFile, uiFlags );
|
||
else
|
||
*szSpFile = '\0';
|
||
if ( hFile == FS_ERROR )
|
||
bRetry = ( hb_cdxErrorRT( pArea, EG_OPEN, 1003, *szSpFile ? (char *) szSpFile : szFileName,
|
||
EF_CANRETRY | EF_CANDEFAULT ) == E_RETRY );
|
||
else
|
||
bRetry = FALSE;
|
||
|
||
} while ( bRetry );
|
||
|
||
if ( szFileNameDbfPath != NULL )
|
||
hb_xfree( szFileNameDbfPath );
|
||
hb_xfree( szFileName );
|
||
|
||
if ( hFile == FS_ERROR )
|
||
{
|
||
hb_xfree( szBaseName );
|
||
return FAILURE;
|
||
}
|
||
|
||
pIndex = hb_cdxIndexNew( pArea );
|
||
pIndex->hFile = hFile;
|
||
pIndex->szFileName = hb_strdup( (char *) szSpFile );
|
||
if ( pArea->lpIndexes == NULL )
|
||
{
|
||
pArea->lpIndexes = pIndex;
|
||
}
|
||
else
|
||
{
|
||
pIndexTmp = pArea->lpIndexes;
|
||
while ( pIndexTmp->pNext )
|
||
pIndexTmp = pIndexTmp->pNext;
|
||
pIndexTmp->pNext = pIndex;
|
||
}
|
||
|
||
/* TODO: check if index file is not corrupted */
|
||
hb_cdxIndexLoad( pIndex, szBaseName );
|
||
hb_xfree( szBaseName );
|
||
|
||
/* dbfcdx specific: If there was no controlling order, set this one.
|
||
* This is the behaviour of Clipper's dbfcdx, although
|
||
* Clipper doc says a different rule
|
||
*/
|
||
if ( ! pArea->uiTag )
|
||
{
|
||
pArea->uiTag = hb_cdxGetTagNumber( pArea, pIndex->TagList );
|
||
SELF_GOTOP( ( AREAP ) pArea );
|
||
}
|
||
return SUCCESS;
|
||
}
|
||
|
||
/* ( DBENTRYP_V ) hb_cdxOrderListClear */
|
||
/*
|
||
* Clear the current order list.
|
||
*/
|
||
static ERRCODE hb_cdxOrderListClear( CDXAREAP pArea )
|
||
{
|
||
HB_TRACE(HB_TR_DEBUG, ("cdxOrderListClear(%p)", pArea));
|
||
|
||
if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE )
|
||
return FAILURE;
|
||
|
||
hb_cdxOrdListClear( pArea, FALSE, NULL );
|
||
pArea->uiTag = 0;
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
/* TODO: in the future, now there is no API call to SELF_ORDLSTDELETE */
|
||
/* ( DBENTRYP_VP ) hb_cdxOrderListDelete : NULL */
|
||
|
||
/* ( DBENTRYP_OI ) hb_cdxOrderListFocus */
|
||
static ERRCODE hb_cdxOrderListFocus( CDXAREAP pArea, LPDBORDERINFO pOrderInfo )
|
||
{
|
||
LPCDXTAG pTag;
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("cdxOrderListFocus(%p, %p)", pArea, pOrderInfo));
|
||
|
||
if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE )
|
||
return FAILURE;
|
||
|
||
if ( ! pArea->lpIndexes )
|
||
return SUCCESS;
|
||
|
||
pTag = hb_cdxGetActiveTag( pArea );
|
||
if ( pTag )
|
||
pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, pTag->szName );
|
||
|
||
if ( pOrderInfo->itmOrder )
|
||
pArea->uiTag = hb_cdxFindTag( pArea, pOrderInfo->itmOrder );
|
||
/* TODO: RTerror if not found? */
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
/* ( DBENTRYP_V ) hb_cdxOrderListRebuild */
|
||
static ERRCODE hb_cdxOrderListRebuild( CDXAREAP pArea )
|
||
{
|
||
LPCDXINDEX pIndex, * pIndexPtr;
|
||
USHORT uiPrevTag;
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("nb_cdxPack(%p)", pArea ));
|
||
|
||
if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE )
|
||
return FAILURE;
|
||
|
||
if ( pArea->fShared )
|
||
{
|
||
hb_cdxErrorRT( pArea, EG_SHARED, EDBF_SHARED, pArea->szDataFileName, 0 );
|
||
return FAILURE;
|
||
}
|
||
if ( pArea->fReadonly )
|
||
{
|
||
hb_cdxErrorRT( pArea, EG_READONLY, EDBF_READONLY, pArea->szDataFileName, 0 );
|
||
return FAILURE;
|
||
}
|
||
|
||
if ( ! pArea->lpIndexes )
|
||
return SUCCESS;
|
||
|
||
uiPrevTag = pArea->uiTag;
|
||
pArea->uiTag = 0;
|
||
|
||
pIndex = pArea->lpIndexes;
|
||
pArea->lpIndexes = NULL;
|
||
pIndexPtr = &pArea->lpIndexes;
|
||
while ( pIndex )
|
||
{
|
||
(*pIndexPtr) = pIndex;
|
||
pIndex = pIndex->pNext;
|
||
(*pIndexPtr)->pNext = NULL;
|
||
hb_cdxIndexReindex( *pIndexPtr );
|
||
pIndexPtr = &(*pIndexPtr)->pNext;
|
||
}
|
||
|
||
pArea->uiTag = uiPrevTag;
|
||
/* Clear pArea->lpdbOrdCondInfo */
|
||
SELF_ORDSETCOND( ( AREAP ) pArea, NULL );
|
||
|
||
return SELF_GOTOP( ( AREAP ) pArea );
|
||
}
|
||
|
||
/* ( DBENTRYP_VOI ) hb_cdxOrderCondition : NULL */
|
||
|
||
/* ( DBENTRYP_VOC ) hb_cdxOrderCreate */
|
||
/*
|
||
* create new order
|
||
*/
|
||
static ERRCODE hb_cdxOrderCreate( CDXAREAP pArea, LPDBORDERCREATEINFO pOrderInfo )
|
||
{
|
||
ULONG ulRecNo;
|
||
BOOL fNewFile, fOpenedIndex;
|
||
PHB_ITEM pKeyExp, pForExp, pResult;
|
||
HB_MACRO_PTR pExpMacro, pForMacro;
|
||
char * szFileName, * szCpndTagName, * szTagName;
|
||
BYTE szSpFile[ _POSIX_PATH_MAX + 3 + 10 ];
|
||
PHB_FNAME pFileName;
|
||
DBORDERINFO pExtInfo;
|
||
LPCDXINDEX pIndex;
|
||
LPCDXTAG pTag;
|
||
USHORT uiType, uiLen;
|
||
BYTE bType;
|
||
|
||
pForExp = NULL;
|
||
pExpMacro = pForMacro = NULL;
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("cdxOrderCreate(%p, %p)", pArea, pOrderInfo));
|
||
|
||
if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE )
|
||
return FAILURE;
|
||
|
||
/* If we have a codeblock for the expression, use it */
|
||
if ( pOrderInfo->itmCobExpr )
|
||
pKeyExp = hb_itemNew( pOrderInfo->itmCobExpr );
|
||
else /* Otherwise, try compiling the key expression string */
|
||
{
|
||
if ( SELF_COMPILE( (AREAP) pArea, ( BYTE * ) pOrderInfo->abExpr->item.asString.value ) == FAILURE )
|
||
return FAILURE;
|
||
pKeyExp = pArea->valResult;
|
||
pArea->valResult = NULL;
|
||
}
|
||
|
||
/* Get a blank record before testing expression */
|
||
ulRecNo = pArea->ulRecNo;
|
||
SELF_GOTO( ( AREAP ) pArea, 0 );
|
||
if ( hb_itemType( pKeyExp ) == HB_IT_BLOCK )
|
||
{
|
||
if ( SELF_EVALBLOCK( ( AREAP ) pArea, pKeyExp ) == FAILURE )
|
||
{
|
||
hb_itemRelease( pKeyExp );
|
||
SELF_GOTO( ( AREAP ) pArea, ulRecNo );
|
||
return FAILURE;
|
||
}
|
||
pResult = pArea->valResult;
|
||
pArea->valResult = NULL;
|
||
}
|
||
else
|
||
{
|
||
pExpMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pKeyExp );
|
||
hb_cdxMacroRun( pArea, pExpMacro );
|
||
pResult = hb_itemNew( hb_stackItemFromTop( -1 ) );
|
||
}
|
||
uiType = hb_itemType( pResult );
|
||
switch ( uiType )
|
||
{
|
||
case HB_IT_INTEGER:
|
||
case HB_IT_LONG:
|
||
#ifndef HB_LONG_LONG_OFF
|
||
case HB_IT_LONGLONG:
|
||
#endif
|
||
case HB_IT_DOUBLE:
|
||
bType = 'N';
|
||
uiLen = 8;
|
||
break;
|
||
case HB_IT_DATE:
|
||
bType = 'D';
|
||
uiLen = 8;
|
||
break;
|
||
case HB_IT_LOGICAL:
|
||
bType = 'L';
|
||
uiLen = 1;
|
||
break;
|
||
case HB_IT_STRING:
|
||
bType = 'C';
|
||
uiLen = HB_CDXMAXKEY( pResult->item.asString.length );
|
||
break;
|
||
default:
|
||
hb_itemRelease( pKeyExp );
|
||
if ( pExpMacro != NULL )
|
||
hb_macroDelete( pExpMacro );
|
||
SELF_GOTO( ( AREAP ) pArea, ulRecNo );
|
||
/* TODO: !!! runtime error ? */
|
||
return FAILURE;
|
||
}
|
||
hb_itemRelease( pResult );
|
||
if ( uiLen == 0 )
|
||
{
|
||
hb_itemRelease( pKeyExp );
|
||
if ( pExpMacro != NULL )
|
||
hb_macroDelete( pExpMacro );
|
||
SELF_GOTO( ( AREAP ) pArea, ulRecNo );
|
||
hb_cdxErrorRT( pArea, EG_DATAWIDTH, 1026, NULL, 0 );
|
||
return FAILURE;
|
||
}
|
||
/* Check conditional expression */
|
||
if ( pArea->lpdbOrdCondInfo )
|
||
{
|
||
/* If we have a codeblock for the conditional expression, use it */
|
||
if ( pArea->lpdbOrdCondInfo->itmCobFor )
|
||
pForExp = hb_itemNew( pArea->lpdbOrdCondInfo->itmCobFor );
|
||
else /* Otherwise, try compiling the conditional expression string */
|
||
{
|
||
if ( pArea->lpdbOrdCondInfo->abFor )
|
||
{
|
||
if ( SELF_COMPILE( (AREAP) pArea, pArea->lpdbOrdCondInfo->abFor ) == FAILURE )
|
||
{
|
||
hb_itemRelease( pKeyExp );
|
||
if ( pExpMacro != NULL )
|
||
hb_macroDelete( pExpMacro );
|
||
SELF_GOTO( ( AREAP ) pArea, ulRecNo );
|
||
return FAILURE;
|
||
}
|
||
pForExp = pArea->valResult;
|
||
pArea->valResult = NULL;
|
||
}
|
||
}
|
||
}
|
||
/* Test conditional expression */
|
||
if ( pForExp )
|
||
{
|
||
if ( hb_itemType( pForExp ) == HB_IT_BLOCK )
|
||
{
|
||
if ( SELF_EVALBLOCK( ( AREAP ) pArea, pForExp ) == FAILURE )
|
||
{
|
||
hb_itemRelease( pKeyExp );
|
||
hb_itemRelease( pForExp );
|
||
if ( pExpMacro != NULL )
|
||
hb_macroDelete( pExpMacro );
|
||
SELF_GOTO( ( AREAP ) pArea, ulRecNo );
|
||
return FAILURE;
|
||
}
|
||
uiType = hb_itemType( pArea->valResult );
|
||
hb_itemRelease( pArea->valResult );
|
||
pArea->valResult = NULL;
|
||
}
|
||
else
|
||
{
|
||
pForMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pForExp );
|
||
hb_cdxMacroRun( pArea, pForMacro );
|
||
uiType = hb_itemType( hb_stackItemFromTop( -1 ) );
|
||
}
|
||
if ( uiType != HB_IT_LOGICAL )
|
||
{
|
||
hb_itemRelease( pKeyExp );
|
||
hb_itemRelease( pForExp );
|
||
if ( pExpMacro != NULL )
|
||
hb_macroDelete( pExpMacro );
|
||
if ( pForMacro != NULL )
|
||
hb_macroDelete( pForMacro );
|
||
SELF_GOTO( ( AREAP ) pArea, ulRecNo );
|
||
/* TODO: !!! runtime error ? */
|
||
return FAILURE;
|
||
}
|
||
}
|
||
/* Check file name */
|
||
szFileName = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 3 );
|
||
szFileName[ 0 ] = '\0';
|
||
if ( !pOrderInfo->abBagName || ( strlen( ( char * ) pOrderInfo->abBagName ) == 0 ) )
|
||
{
|
||
pFileName = hb_fsFNameSplit( pArea->szDataFileName );
|
||
if ( pFileName->szPath )
|
||
strcat( szFileName, pFileName->szPath );
|
||
strcat( szFileName, pFileName->szName );
|
||
pExtInfo.itmResult = hb_itemPutC( NULL, "" );
|
||
SELF_ORDINFO( ( AREAP ) pArea, DBOI_BAGEXT, &pExtInfo );
|
||
strcat( szFileName, pExtInfo.itmResult->item.asString.value );
|
||
hb_itemRelease( pExtInfo.itmResult );
|
||
}
|
||
else
|
||
{
|
||
strcpy( szFileName, ( char * ) pOrderInfo->abBagName );
|
||
pFileName = hb_fsFNameSplit( szFileName );
|
||
if ( !pFileName->szExtension )
|
||
{
|
||
pExtInfo.itmResult = hb_itemPutC( NULL, "" );
|
||
SELF_ORDINFO( ( AREAP ) pArea, DBOI_BAGEXT, &pExtInfo );
|
||
strcat( szFileName, pExtInfo.itmResult->item.asString.value );
|
||
hb_itemRelease( pExtInfo.itmResult );
|
||
}
|
||
}
|
||
szTagName = ( char * ) hb_xgrab( CDX_MAXTAGNAMELEN + 1 );
|
||
szCpndTagName = ( char * ) hb_xgrab( CDX_MAXTAGNAMELEN + 1 );
|
||
hb_strncpyUpperTrim( szCpndTagName, pFileName->szName, CDX_MAXTAGNAMELEN );
|
||
hb_xfree( pFileName );
|
||
if ( pOrderInfo->atomBagName && ( strlen( ( char * ) pOrderInfo->atomBagName ) > 0 ) )
|
||
hb_strncpyUpperTrim( szTagName, ( char * ) pOrderInfo->atomBagName, CDX_MAXTAGNAMELEN );
|
||
else
|
||
strcpy( szTagName, szCpndTagName );
|
||
|
||
if ( !pArea->lpdbOrdCondInfo ||
|
||
( pArea->lpdbOrdCondInfo->fAll && !pArea->lpdbOrdCondInfo->fAdditive ) )
|
||
hb_cdxOrdListClear( pArea, FALSE, NULL );
|
||
|
||
pIndex = hb_cdxFindBag( pArea, szFileName );
|
||
fOpenedIndex = ( pIndex != NULL );
|
||
fNewFile = FALSE;
|
||
|
||
if ( !fOpenedIndex )
|
||
{
|
||
FHANDLE hFile;
|
||
fNewFile = ! hb_spFile( ( BYTE * ) szFileName, szSpFile );
|
||
if ( fNewFile )
|
||
{
|
||
/* TODO: no API to take real file name with path */
|
||
hFile = hb_spCreate( ( BYTE * ) szFileName, FC_NORMAL );
|
||
}
|
||
else
|
||
{
|
||
strcpy( szFileName, ( char * ) szSpFile );
|
||
hFile = hb_spOpen( ( BYTE * ) szFileName,
|
||
FO_READWRITE | ( pArea->fShared ? FO_DENYNONE : FO_EXCLUSIVE ) );
|
||
}
|
||
if ( hFile == FS_ERROR )
|
||
{
|
||
hb_xfree( szFileName );
|
||
hb_xfree( szTagName );
|
||
hb_xfree( szCpndTagName );
|
||
hb_itemRelease( pKeyExp );
|
||
if ( pForExp != NULL )
|
||
hb_itemRelease( pForExp );
|
||
if ( pExpMacro != NULL )
|
||
hb_macroDelete( pExpMacro );
|
||
if ( pForMacro != NULL )
|
||
hb_macroDelete( pForMacro );
|
||
SELF_GOTO( ( AREAP ) pArea, ulRecNo );
|
||
/* TODO: !!! runtime error ? */
|
||
return FAILURE;
|
||
}
|
||
pIndex = hb_cdxIndexNew( pArea );
|
||
pIndex->hFile = hFile;
|
||
pIndex->fShared = pArea->fShared;
|
||
pIndex->fReadonly = FALSE;
|
||
pIndex->szFileName = hb_strdup( szFileName );
|
||
|
||
if ( !fNewFile )
|
||
{
|
||
/* TODO: check if index file is not corrupted */
|
||
/* cut corrupted files */
|
||
fNewFile = ( hb_fsSeek( hFile, 0, FS_END ) <= sizeof( CDXTAGHEADER ) );
|
||
}
|
||
if ( !fNewFile )
|
||
hb_cdxIndexLoad( pIndex, szCpndTagName );
|
||
}
|
||
|
||
hb_cdxIndexLockWrite( pIndex );
|
||
if ( !fNewFile )
|
||
{
|
||
/* Delete new tag if exist */
|
||
hb_cdxIndexDelTag( pIndex, szTagName );
|
||
fNewFile = ( pIndex->TagList == NULL );
|
||
}
|
||
|
||
if ( fNewFile )
|
||
{
|
||
hb_fsSeek( pIndex->hFile, 0, FS_SET );
|
||
hb_fsWrite( pIndex->hFile, NULL, 0 );
|
||
hb_cdxIndexDropAvailPage( pIndex );
|
||
if ( pIndex->pCompound != NULL )
|
||
hb_cdxTagFree( pIndex->pCompound );
|
||
pIndex->nextAvail = pIndex->freePage = 0;
|
||
pIndex->pCompound = hb_cdxTagNew( pIndex, szCpndTagName, CDX_DUMMYNODE );
|
||
pIndex->pCompound->OptFlags = CDX_TYPE_COMPACT | CDX_TYPE_COMPOUND | CDX_TYPE_STRUCTURE;
|
||
hb_cdxTagIndexTagNew( pIndex->pCompound, NULL, NULL, 'C', 10, NULL, NULL,
|
||
TRUE, FALSE, FALSE );
|
||
}
|
||
|
||
/* Update DBF header */
|
||
if ( !pArea->fHasTags )
|
||
{
|
||
pFileName = hb_fsFNameSplit( pArea->szDataFileName );
|
||
hb_strncpyUpper( szFileName, pFileName->szName, CDX_MAXTAGNAMELEN );
|
||
hb_xfree( pFileName );
|
||
if ( strcmp( szFileName, szCpndTagName ) == 0 )
|
||
{
|
||
pArea->fHasTags = TRUE;
|
||
SELF_WRITEDBHEADER( ( AREAP ) pArea );
|
||
}
|
||
}
|
||
hb_xfree( szFileName );
|
||
|
||
if ( !pArea->lpdbOrdCondInfo || pArea->lpdbOrdCondInfo->fAll )
|
||
pArea->uiTag = 0;
|
||
|
||
pTag = hb_cdxIndexAddTag( pIndex, szTagName, pOrderInfo->abExpr->item.asString.value,
|
||
pKeyExp, bType, uiLen, ( char * ) ( pArea->lpdbOrdCondInfo ? pArea->lpdbOrdCondInfo->abFor :
|
||
NULL ), pForExp,
|
||
( pArea->lpdbOrdCondInfo ? !pArea->lpdbOrdCondInfo->fDescending : TRUE ) , pOrderInfo->fUnique,
|
||
( pArea->lpdbOrdCondInfo ? pArea->lpdbOrdCondInfo->fCustom : FALSE ) );
|
||
|
||
hb_xfree( szTagName );
|
||
hb_xfree( szCpndTagName );
|
||
if ( pArea->lpdbOrdCondInfo && ( !pArea->lpdbOrdCondInfo->fAll &&
|
||
!pArea->lpdbOrdCondInfo->fAdditive ) )
|
||
{
|
||
hb_cdxOrdListClear( pArea, FALSE, pIndex );
|
||
}
|
||
hb_cdxIndexUnLockWrite( pIndex );
|
||
if ( !fOpenedIndex )
|
||
{
|
||
if ( pArea->lpIndexes == NULL )
|
||
pArea->lpIndexes = pIndex;
|
||
else
|
||
{
|
||
LPCDXINDEX pIndexTmp = pArea->lpIndexes;
|
||
while ( pIndexTmp->pNext )
|
||
pIndexTmp = pIndexTmp->pNext;
|
||
pIndexTmp->pNext = pIndex;
|
||
}
|
||
}
|
||
|
||
pArea->uiTag = hb_cdxGetTagNumber( pArea, pTag );
|
||
|
||
/* Clear pArea->lpdbOrdCondInfo */
|
||
SELF_ORDSETCOND( ( AREAP ) pArea, NULL );
|
||
|
||
return SELF_GOTOP( ( AREAP ) pArea );
|
||
}
|
||
|
||
/* ( DBENTRYP_OI ) hb_cdxOrderDestroy */
|
||
static ERRCODE hb_cdxOrderDestroy( CDXAREAP pArea, LPDBORDERINFO pOrderInfo )
|
||
{
|
||
LPCDXINDEX pIndex, pIndexTmp;
|
||
LPCDXTAG pTag;
|
||
USHORT uiTag;
|
||
char * szFileName;
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("cdxOrderDestroy(%p, %p)", pArea, pOrderInfo));
|
||
|
||
if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE )
|
||
return FAILURE;
|
||
|
||
if ( ! pArea->lpIndexes )
|
||
return SUCCESS;
|
||
|
||
if ( pOrderInfo->itmOrder )
|
||
{
|
||
uiTag = hb_cdxFindTag( pArea, pOrderInfo->itmOrder );
|
||
if ( uiTag )
|
||
{
|
||
pTag = hb_cdxGetTagByNumber( pArea, uiTag );
|
||
pIndex = pTag->pIndex;
|
||
if ( !pIndex->fShared && !pIndex->fReadonly )
|
||
{
|
||
hb_cdxIndexLockWrite( pIndex );
|
||
hb_cdxIndexDelTag( pIndex, pTag->szName );
|
||
hb_cdxIndexUnLockWrite( pIndex );
|
||
if ( !pIndex->TagList )
|
||
{
|
||
if ( pArea->lpIndexes == pIndex )
|
||
{
|
||
pArea->lpIndexes = pIndex->pNext;
|
||
if ( pArea->fHasTags )
|
||
{
|
||
pArea->fHasTags = FALSE;
|
||
SELF_WRITEDBHEADER( ( AREAP ) pArea );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pIndexTmp = pArea->lpIndexes;
|
||
while ( pIndexTmp->pNext && ( pIndexTmp->pNext != pIndex ) )
|
||
{
|
||
pIndexTmp = pIndexTmp->pNext;
|
||
}
|
||
if ( pIndexTmp->pNext == pIndex )
|
||
{
|
||
pIndexTmp->pNext = pIndex->pNext;
|
||
}
|
||
}
|
||
szFileName = hb_strdup( pIndex->szFileName );
|
||
hb_cdxIndexFree( pIndex );
|
||
hb_fsDelete( (BYTE *) szFileName );
|
||
hb_xfree( szFileName );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* TODO: allow this operation for shared mode? */
|
||
hb_errInternal( 1023, "hb_cdxOrderDestroy: exclusive required.", "", "" );
|
||
}
|
||
}
|
||
}
|
||
return SUCCESS;
|
||
}
|
||
|
||
/* ( DBENTRYP_OII ) hb_cdxOrderInfo */
|
||
/*
|
||
* Provides information about order management.
|
||
*/
|
||
static ERRCODE hb_cdxOrderInfo( CDXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pOrderInfo )
|
||
{
|
||
LPCDXTAG pTag = NULL;
|
||
USHORT uiTag = 0;
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("hb_cdxOrderInfo(%p, %hu, %p)", pArea, uiIndex, pOrderInfo));
|
||
|
||
if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE )
|
||
return FAILURE;
|
||
|
||
switch( uiIndex )
|
||
{
|
||
case DBOI_ORDERCOUNT:
|
||
case DBOI_BAGEXT:
|
||
case DBOI_LOCKOFFSET:
|
||
case DBOI_HPLOCKING:
|
||
break;
|
||
default:
|
||
if ( pOrderInfo->itmOrder )
|
||
/* TODO: check for atom bug name (indename) */
|
||
uiTag = hb_cdxFindTag( pArea, pOrderInfo->itmOrder );
|
||
else
|
||
uiTag = pArea->uiTag;
|
||
pTag = hb_cdxGetTagByNumber( pArea, uiTag );
|
||
}
|
||
|
||
switch( uiIndex )
|
||
{
|
||
case DBOI_CONDITION:
|
||
pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, ( pTag ? pTag->ForExpr : "" ) );
|
||
break;
|
||
|
||
case DBOI_EXPRESSION:
|
||
pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, ( pTag ? pTag->KeyExpr : "" ) );
|
||
break;
|
||
|
||
case DBOI_POSITION:
|
||
if ( pOrderInfo->itmNewVal && HB_IS_NUMERIC( pOrderInfo->itmNewVal ) )
|
||
{
|
||
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult,
|
||
hb_cdxDBOIKeyGoto( pArea, pTag,
|
||
hb_itemGetNL( pOrderInfo->itmNewVal ), TRUE ) == SUCCESS );
|
||
}
|
||
else
|
||
pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult,
|
||
hb_cdxDBOIKeyNo( pArea, pTag, TRUE ) );
|
||
break;
|
||
|
||
case DBOI_RECNO: /* TODO: is this ok? DBOI_RECNO == DBOI_KEYNORAW ? */
|
||
case DBOI_KEYNORAW:
|
||
pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult,
|
||
hb_cdxDBOIKeyNo( pArea, pTag, FALSE ) );
|
||
break;
|
||
|
||
case DBOI_KEYCOUNT:
|
||
pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult,
|
||
hb_cdxDBOIKeyCount( pArea, pTag, TRUE ) );
|
||
break;
|
||
|
||
case DBOI_KEYCOUNTRAW:
|
||
pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult,
|
||
hb_cdxDBOIKeyCount( pArea, pTag, FALSE ) );
|
||
break;
|
||
|
||
case DBOI_SKIPUNIQUE:
|
||
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult,
|
||
hb_cdxSkipUnique( pArea, pTag,
|
||
hb_itemGetNI( pOrderInfo->itmNewVal ) >= 0 ) == SUCCESS );
|
||
break;
|
||
|
||
case DBOI_SKIPEVAL:
|
||
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult,
|
||
hb_cdxDBOISkipEval( pArea, pTag, TRUE, pOrderInfo->itmNewVal ) );
|
||
break;
|
||
|
||
case DBOI_SKIPEVALBACK:
|
||
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult,
|
||
hb_cdxDBOISkipEval( pArea, pTag, FALSE, pOrderInfo->itmNewVal ) );
|
||
break;
|
||
|
||
case DBOI_NAME:
|
||
pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, ( pTag ? pTag->szName : "" ) );
|
||
break;
|
||
|
||
case DBOI_NUMBER:
|
||
pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, uiTag );
|
||
break;
|
||
|
||
case DBOI_BAGNAME:
|
||
if ( pTag )
|
||
{
|
||
PHB_FNAME pFileName = hb_fsFNameSplit( pTag->pIndex->szFileName );
|
||
pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, pFileName->szName );
|
||
hb_xfree( pFileName );
|
||
}
|
||
else
|
||
pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, "" );
|
||
break;
|
||
|
||
case DBOI_FULLPATH:
|
||
pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, ( pTag ? pTag->pIndex->szFileName : "" ) );
|
||
break;
|
||
|
||
case DBOI_BAGEXT:
|
||
pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, CDX_INDEXEXT );
|
||
break;
|
||
|
||
case DBOI_HPLOCKING:
|
||
case DBOI_LOCKOFFSET:
|
||
{
|
||
ULONG ulPos, ulPool;
|
||
|
||
hb_dbfLockIdxGetData( pArea->bLockType, &ulPos, &ulPool );
|
||
if ( uiIndex == DBOI_LOCKOFFSET )
|
||
pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, ulPos );
|
||
else
|
||
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, ulPool > 0 );
|
||
break;
|
||
}
|
||
|
||
case DBOI_ORDERCOUNT:
|
||
uiTag = 0;
|
||
if ( pArea->lpIndexes )
|
||
{
|
||
pTag = pArea->lpIndexes->TagList;
|
||
while ( pTag )
|
||
{
|
||
uiTag++;
|
||
if ( pTag->pNext )
|
||
pTag = pTag->pNext;
|
||
else
|
||
{
|
||
if ( pTag->pIndex->pNext )
|
||
pTag = pTag->pIndex->pNext->TagList;
|
||
else
|
||
pTag = NULL;
|
||
}
|
||
}
|
||
}
|
||
pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, uiTag );
|
||
break;
|
||
|
||
case DBOI_FILEHANDLE:
|
||
pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, ( pTag ? ( LONG ) pTag->pIndex->hFile : FS_ERROR ) );
|
||
break;
|
||
|
||
case DBOI_ISCOND:
|
||
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, ( pTag ? (pTag->ForExpr != NULL) : FALSE ) );
|
||
break;
|
||
|
||
case DBOI_ISDESC:
|
||
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, ( pTag ? !pTag->UsrAscend : FALSE ) );
|
||
if ( pOrderInfo->itmNewVal && HB_IS_LOGICAL( pOrderInfo->itmNewVal ) )
|
||
pTag->UsrAscend = ! hb_itemGetL( pOrderInfo->itmNewVal );
|
||
break;
|
||
|
||
case DBOI_UNIQUE:
|
||
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, ( pTag ? pTag->UniqueKey || pTag->UsrUnique : FALSE ) );
|
||
if ( pOrderInfo->itmNewVal && HB_IS_LOGICAL( pOrderInfo->itmNewVal ) && !pTag->UniqueKey )
|
||
pTag->UsrUnique = hb_itemGetL( pOrderInfo->itmNewVal );
|
||
break;
|
||
|
||
case DBOI_KEYTYPE:
|
||
if ( pTag )
|
||
{
|
||
char szType[2];
|
||
szType[0] = (char) pTag->uiType;
|
||
szType[1] = 0;
|
||
pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, szType );
|
||
}
|
||
else
|
||
pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, "" );
|
||
break;
|
||
|
||
case DBOI_KEYSIZE:
|
||
if ( pTag )
|
||
pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, pTag->uiLen );
|
||
else
|
||
pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, 0 );
|
||
break;
|
||
|
||
case DBOI_KEYVAL:
|
||
hb_itemClear( pOrderInfo->itmResult );
|
||
if ( pTag && !pArea->fEof )
|
||
{
|
||
if ( pTag->CurKey->rec != pArea->ulRecNo )
|
||
{
|
||
hb_cdxIndexLockRead( pTag->pIndex );
|
||
hb_cdxCurKeyRefresh( pArea, pTag, FALSE );
|
||
hb_cdxIndexUnLockRead( pTag->pIndex );
|
||
}
|
||
if ( pTag->CurKey->rec == pArea->ulRecNo )
|
||
hb_cdxKeyGetItem( pTag->CurKey, pOrderInfo->itmResult, pTag->uiType );
|
||
}
|
||
break;
|
||
|
||
case DBOI_SCOPETOP:
|
||
if ( pTag )
|
||
hb_cdxScopeInfo( pArea, 0, pOrderInfo->itmResult );
|
||
else
|
||
hb_itemClear( pOrderInfo->itmResult );
|
||
break;
|
||
|
||
case DBOI_SCOPEBOTTOM:
|
||
if ( pTag )
|
||
hb_cdxScopeInfo( pArea, 1, pOrderInfo->itmResult );
|
||
else
|
||
hb_itemClear( pOrderInfo->itmResult );
|
||
break;
|
||
|
||
case DBOI_SCOPETOPCLEAR:
|
||
if ( pTag )
|
||
{
|
||
hb_cdxScopeInfo( pArea, 0, pOrderInfo->itmResult );
|
||
hb_cdxTagClearScope( pTag, 0);
|
||
}
|
||
else
|
||
hb_itemClear( pOrderInfo->itmResult );
|
||
break;
|
||
|
||
case DBOI_SCOPEBOTTOMCLEAR:
|
||
if ( pTag )
|
||
{
|
||
hb_cdxScopeInfo( pArea, 1, pOrderInfo->itmResult );
|
||
hb_cdxTagClearScope( pTag, 1);
|
||
}
|
||
else
|
||
hb_itemClear( pOrderInfo->itmResult );
|
||
break;
|
||
|
||
case DBOI_CUSTOM:
|
||
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, ( pTag ? pTag->Custom : FALSE ) );
|
||
break;
|
||
|
||
case DBOI_KEYADD:
|
||
if ( !pTag )
|
||
{
|
||
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, FALSE );
|
||
}
|
||
else
|
||
{
|
||
if ( pTag->Custom )
|
||
{
|
||
LPCDXKEY pKey;
|
||
hb_cdxIndexLockWrite( pTag->pIndex );
|
||
if ( pOrderInfo->itmNewVal && !HB_IS_NIL( pOrderInfo->itmNewVal ) )
|
||
pKey = hb_cdxKeyPutItem( NULL, pOrderInfo->itmNewVal, pArea->ulRecNo, pTag, TRUE, TRUE );
|
||
else
|
||
pKey = hb_cdxKeyEval( NULL, pTag, TRUE );
|
||
hb_cdxTagKeyAdd( pTag, pKey );
|
||
if ( uiTag != pArea->uiTag )
|
||
hb_cdxTagClose( pTag );
|
||
hb_cdxIndexUnLockWrite( pTag->pIndex );
|
||
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, TRUE );
|
||
hb_cdxKeyFree( pKey );
|
||
}
|
||
else
|
||
{
|
||
hb_cdxErrorRT( pArea, 0, 1052, "", 0 );
|
||
}
|
||
}
|
||
break;
|
||
|
||
case DBOI_KEYDELETE:
|
||
if ( !pTag )
|
||
{
|
||
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, FALSE );
|
||
}
|
||
else
|
||
{
|
||
if ( pTag->Custom )
|
||
{
|
||
LPCDXKEY pKey;
|
||
hb_cdxIndexLockWrite( pTag->pIndex );
|
||
if ( pOrderInfo->itmNewVal && !HB_IS_NIL( pOrderInfo->itmNewVal ) )
|
||
pKey = hb_cdxKeyPutItem( NULL, pOrderInfo->itmNewVal, pArea->ulRecNo, pTag, TRUE, TRUE );
|
||
else
|
||
pKey = hb_cdxKeyEval( NULL, pTag, TRUE );
|
||
if ( hb_cdxTagKeyFind( pTag, pKey ) > 0 )
|
||
{
|
||
hb_cdxPageKeyDelete( pTag->RootPage );
|
||
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, TRUE );
|
||
}
|
||
else
|
||
{
|
||
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, FALSE );
|
||
}
|
||
if ( uiTag != pArea->uiTag )
|
||
hb_cdxTagClose( pTag );
|
||
hb_cdxIndexUnLockWrite( pTag->pIndex );
|
||
hb_cdxKeyFree( pKey );
|
||
}
|
||
else
|
||
{
|
||
hb_cdxErrorRT( pArea, 0, 1052, "", 0 );
|
||
}
|
||
}
|
||
break;
|
||
|
||
default:
|
||
return SUPER_ORDINFO( ( AREAP ) pArea, uiIndex, pOrderInfo );
|
||
|
||
}
|
||
return SUCCESS;
|
||
}
|
||
|
||
/* ( DBENTRYP_V ) hb_cdxClearFilter : NULL */
|
||
/* ( DBENTRYP_V ) hb_cdxClearLocate : NULL */
|
||
|
||
/* ( DBENTRYP_V ) hb_cdxClearScope */
|
||
static ERRCODE hb_cdxClearScope( CDXAREAP pArea )
|
||
{
|
||
LPCDXTAG pTag;
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("hb_cdxClearScope(%p)", pArea));
|
||
|
||
pTag = hb_cdxGetActiveTag( pArea );
|
||
|
||
if ( pTag )
|
||
{
|
||
hb_cdxTagClearScope( pTag, 0);
|
||
hb_cdxTagClearScope( pTag, 1);
|
||
}
|
||
return SUCCESS;
|
||
}
|
||
|
||
/* ( DBENTRYP_VPLP ) hb_cdxCountScope : NULL */
|
||
/* ( DBENTRYP_I ) hb_cdxFilterText : NULL */
|
||
|
||
/* ( DBENTRYP_SI ) hb_cdxScopeInfo */
|
||
static ERRCODE hb_cdxScopeInfo( CDXAREAP pArea, USHORT nScope, PHB_ITEM pItem )
|
||
{
|
||
LPCDXTAG pTag;
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("hb_cdxScopeInfo(%p, %hu, %p)", pArea, nScope, pItem));
|
||
|
||
pTag = hb_cdxGetActiveTag( pArea );
|
||
|
||
hb_itemClear( pItem );
|
||
if ( pTag )
|
||
{
|
||
PHB_ITEM *pScope;
|
||
|
||
nScope = ( ( nScope == 0 ) ? 0 : 1 ) ^ ( pTag->UsrAscend ? 0 : 1 );
|
||
pScope = ( nScope == 0 ) ? &(pTag->topScope) : &(pTag->bottomScope);
|
||
if ( *pScope )
|
||
hb_itemCopy( pItem, *pScope );
|
||
}
|
||
return SUCCESS;
|
||
}
|
||
|
||
/* ( DBENTRYP_VFI ) hb_cdxSetFilter : NULL */
|
||
/* ( DBENTRYP_VLO ) hb_cdxSetLocate : NULL */
|
||
|
||
/* ( DBENTRYP_VOS ) hb_cdxSetScope */
|
||
static ERRCODE hb_cdxSetScope( CDXAREAP pArea, LPDBORDSCOPEINFO sInfo )
|
||
{
|
||
USHORT nScope = sInfo->nScope;
|
||
LPCDXTAG pTag;
|
||
|
||
HB_TRACE(HB_TR_DEBUG, ("hb_cdxSetScope(%p, %p)", pArea, sInfo));
|
||
|
||
pTag = hb_cdxGetActiveTag( pArea );
|
||
|
||
if ( pTag )
|
||
{
|
||
nScope = ( ( nScope == 0 ) ? 0 : 1 ) ^ ( pTag->UsrAscend ? 0 : 1 );
|
||
|
||
if ( !sInfo->scopeValue )
|
||
{
|
||
hb_cdxTagClearScope( pTag, nScope );
|
||
}
|
||
else
|
||
{
|
||
PHB_ITEM *pScope;
|
||
LPCDXKEY *pScopeKey;
|
||
USHORT type;
|
||
BOOL fOK, fCB = FALSE;
|
||
|
||
pScope = (nScope == 0) ? &(pTag->topScope) : &(pTag->bottomScope);
|
||
pScopeKey = (nScope == 0) ? &(pTag->topScopeKey) : &(pTag->bottomScopeKey);
|
||
type = sInfo->scopeValue->type;
|
||
if ( type == HB_IT_BLOCK )
|
||
{
|
||
hb_vmPushSymbol( &hb_symEval );
|
||
hb_vmPush( sInfo->scopeValue );
|
||
hb_vmSend( 0 );
|
||
type = HB_VM_STACK.Return.type;
|
||
fCB = TRUE;
|
||
}
|
||
//printf("\r\ntype=%lx", type);fflush(stdout);
|
||
|
||
switch ( pTag->uiType )
|
||
{
|
||
case 'C' :
|
||
fOK = ( type & HB_IT_STRING ); break;
|
||
case 'N' :
|
||
fOK = ( type & HB_IT_NUMERIC ); break;
|
||
case 'D' :
|
||
fOK = ( type == HB_IT_DATE ); break;
|
||
case 'L' :
|
||
fOK = ( type == HB_IT_LOGICAL ); break;
|
||
default:
|
||
fOK = FALSE;
|
||
}
|
||
if ( fOK )
|
||
{
|
||
if ( *pScope == NULL )
|
||
*pScope = hb_itemNew( NULL );
|
||
hb_itemCopy( *pScope, sInfo->scopeValue );
|
||
*pScopeKey = hb_cdxKeyPutItem( *pScopeKey,
|
||
fCB ? &(HB_VM_STACK.Return) : sInfo->scopeValue,
|
||
(nScope == 0) ? CDX_IGNORE_REC_NUM : CDX_MAX_REC_NUM,
|
||
pTag, TRUE, FALSE );
|
||
}
|
||
else
|
||
{
|
||
/* TODO: !!!
|
||
* RT error: DBFCDX/1051 Scope Type Mismatch
|
||
* hb_cdxErrorRT
|
||
*/
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* TODO: !!!
|
||
* RT error: hb_cdxSetScope: workarea not indexed
|
||
*/
|
||
}
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
/* ( DBENTRYP_VPL ) hb_cdxSkipScope : NULL */
|
||
|
||
/* ( DBENTRYP_P ) hb_cdxCompile : NULL */
|
||
/* ( DBENTRYP_I ) hb_cdxError : NULL */
|
||
/* ( DBENTRYP_I ) hb_cdxEvalBlock : NULL */
|
||
|
||
/* ( DBENTRYP_VSP ) hb_cdxRawLock : NULL */
|
||
/* ( DBENTRYP_VL ) hb_cdxLock : NULL */
|
||
/* ( DBENTRYP_UL ) hb_cdxUnLock : NULL */
|
||
|
||
/* ( DBENTRYP_V ) hb_cdxCloseMemFile : NULL */
|
||
/* ( DBENTRYP_VP ) hb_cdxCreateMemFile : NULL */
|
||
/* ( DBENTRYP_SVPB ) hb_cdxGetValueFile : NULL */
|
||
/* ( DBENTRYP_VP ) hb_cdxOpenMemFile : NULL */
|
||
/* ( DBENTRYP_SVP ) hb_cdxPutValueFile : NULL */
|
||
|
||
/* ( DBENTRYP_V ) hb_cdxReadDBHeader : NULL */
|
||
/* ( DBENTRYP_V ) hb_cdxWriteDBHeader : NULL */
|
||
/* ( DBENTRYP_SVP ) hb_cdxWhoCares : NULL */
|
||
|
||
|
||
|
||
/* ######################################################################### */
|
||
/* ######################################################################### */
|
||
/* ######################################################################### */
|
||
/* ######################################################################### */
|
||
|
||
#include "dbfcdx1.h"
|
||
|
||
/* ######################################################################### */
|
||
static LPSORTINFO hb_cdxSortNew( LPCDXTAG pTag, BOOL bUnique );
|
||
static void hb_cdxSortFree( LPSORTINFO pSort );
|
||
static void hb_cdxSortLinkNew( LPSORTINFO pSort, LONG * NewLink );
|
||
static void hb_cdxSortGetNewChunk( LPSORTINFO pSort );
|
||
static void hb_cdxSortInsertWord( LPSORTINFO pSort, LONG Tag, char * Value,
|
||
USHORT uiLen );
|
||
static void hb_cdxSortStuffKey( LPSORTINFO pSort, LPSORTDATA * wx, BOOL fTag );
|
||
static void hb_cdxSortGetNode( LPSORTINFO pSort, BYTE Character,
|
||
LONG * NewLink, BOOL fTag );
|
||
static LPSORTDATA hb_cdxSortLinkGet( LPSORTINFO pSort, LONG Value );
|
||
static void hb_cdxSortDisplayWord( LPSORTINFO pSort );
|
||
static void hb_cdxSortRecurseDict( LPSORTINFO pSort, LONG WPtr, LONG WBgn );
|
||
static void hb_cdxSortSendWord( LPSORTINFO pSort, BYTE * Value );
|
||
static void hb_cdxSortOutputWord( LPSORTINFO pSort, LONG Tag, BYTE * Value,
|
||
USHORT uiLen );
|
||
static void hb_cdxSortAddToNode( LPSORTINFO pSort, USHORT Lvl, LONG Tag, LONG Link,
|
||
LPCDXKEYINFO Value );
|
||
static void hb_cdxSortAddExternal( LPSORTINFO pSort, USHORT Lvl, LONG Tag, LONG Link,
|
||
LPCDXKEYINFO Value );
|
||
static void hb_cdxSortAddInternal( LPSORTINFO pSort, USHORT Lvl, LONG Tag, LONG Link,
|
||
LPCDXKEYINFO Value );
|
||
/* ######################################################################### */
|
||
|
||
static LPCDXKEYINFO hb_cdxSortKeyNew( void )
|
||
{
|
||
LPCDXKEYINFO pKey;
|
||
pKey = ( LPCDXKEYINFO ) hb_xgrab( sizeof( CDXKEYINFO ) );
|
||
memset( pKey, 0, sizeof( CDXKEYINFO ) );
|
||
return pKey;
|
||
}
|
||
|
||
static void hb_cdxSortKeyFree( LPCDXKEYINFO pKey )
|
||
{
|
||
if ( pKey )
|
||
{
|
||
if ( pKey->Value )
|
||
hb_xfree( pKey->Value );
|
||
hb_xfree( pKey );
|
||
}
|
||
}
|
||
|
||
static LPCDXKEYINFO hb_cdxSortKeyCopy( LPCDXKEYINFO pKeyDest, LPCDXKEYINFO pKey )
|
||
{
|
||
if ( !pKeyDest )
|
||
pKeyDest = hb_cdxSortKeyNew();
|
||
if ( pKeyDest->Value )
|
||
{
|
||
hb_xfree( pKeyDest->Value );
|
||
pKeyDest->Value = NULL;
|
||
pKeyDest->length = pKeyDest->realLength = 0;
|
||
}
|
||
if ( pKey )
|
||
{
|
||
pKeyDest->Value = (BYTE *) hb_xgrab( pKey->length + 1 );
|
||
memcpy( pKeyDest->Value, pKey->Value, pKey->length );
|
||
pKeyDest->length = pKey->length;
|
||
pKeyDest->realLength = pKey->realLength;
|
||
pKeyDest->Value[ pKeyDest->length ] = '\0';
|
||
pKeyDest->fString = pKey->fString;
|
||
pKeyDest->Tag = pKey->Tag;
|
||
pKeyDest->Xtra = pKey->Xtra;
|
||
}
|
||
return pKeyDest;
|
||
}
|
||
|
||
static LPCDXKEYINFO hb_cdxSortKeyPut( LPCDXKEYINFO pKey, BYTE * pbVal, USHORT uiLen, USHORT uiRealLen, BOOL fString )
|
||
{
|
||
if ( !pKey )
|
||
pKey = hb_cdxSortKeyNew();
|
||
if ( pKey->Value )
|
||
{
|
||
hb_xfree( pKey->Value );
|
||
pKey->Value = NULL;
|
||
}
|
||
pKey->realLength = uiRealLen;
|
||
pKey->fString = fString;
|
||
if ( pbVal == NULL )
|
||
pKey->length = 0;
|
||
else
|
||
{
|
||
if ( uiLen > uiRealLen )
|
||
uiLen = uiRealLen;
|
||
pKey->length = uiLen;
|
||
pKey->Value = ( BYTE * ) hb_xgrab( uiLen + 1 );
|
||
memcpy( pKey->Value, pbVal, uiLen );
|
||
pKey->Value[ uiLen ] = '\0';
|
||
}
|
||
return pKey;
|
||
}
|
||
|
||
static SHORT hb_cdxSortKeyFindDup( LPCDXKEYINFO pKey1, LPCDXKEYINFO pKey2 )
|
||
{
|
||
SHORT usDup = 0;
|
||
if ( pKey2 != NULL )
|
||
{
|
||
int iLimit = (pKey1->length > pKey2->length) ? pKey2->length : pKey1->length;
|
||
while ( usDup < iLimit && ( (BYTE) pKey1->Value[ usDup ] ) ==
|
||
( (BYTE) pKey2->Value[ usDup ] ) )
|
||
{
|
||
usDup++;
|
||
}
|
||
}
|
||
return usDup;
|
||
}
|
||
|
||
#ifndef HB_CDP_SUPPORT_OFF
|
||
static int hb_cdxSortKeyCompare( LPCDXKEYINFO pKey1, LPCDXKEYINFO pKey2, PHB_CODEPAGE cdpage )
|
||
#else
|
||
static int hb_cdxSortKeyCompare( LPCDXKEYINFO pKey1, LPCDXKEYINFO pKey2 )
|
||
#endif
|
||
{
|
||
int iLimit, iResult = 0, iPos = 0;
|
||
if ( pKey1 == NULL )
|
||
return ( pKey2 == NULL ) ? 0 : -1;
|
||
if ( pKey2 == NULL )
|
||
return 1;
|
||
iLimit = (pKey1->length > pKey2->length) ? pKey2->length : pKey1->length;
|
||
if ( pKey1->fString && pKey2->fString)
|
||
{
|
||
#ifndef HB_CDP_SUPPORT_OFF
|
||
while ( iResult == 0 && iPos < iLimit )
|
||
{
|
||
/* for nation sorting support */
|
||
iResult = hb_cdpcharcmp( pKey1->Value[ iPos ], pKey2->Value[ iPos ], cdpage );
|
||
iPos++; /* EndPos += 1; */
|
||
}
|
||
#else
|
||
if ( iLimit > 0 )
|
||
iResult = memcmp(pKey1->Value, pKey2->Value, iLimit);
|
||
#endif
|
||
if ( iResult == 0 )
|
||
{
|
||
BYTE c1, c2;
|
||
iPos = iLimit;
|
||
iLimit = ( pKey1->realLength > pKey2->realLength ) ? pKey2->realLength : pKey1->realLength;
|
||
while ( iResult == 0 && iPos < iLimit )
|
||
{
|
||
c1 = (BYTE) ( ( iPos < pKey1->length ) ? ( pKey1->Value[ iPos ]) : ' ' );
|
||
c2 = (BYTE) ( ( iPos < pKey2->length ) ? ( pKey2->Value[ iPos ]) : ' ' );
|
||
#ifndef HB_CDP_SUPPORT_OFF
|
||
/* for nation sorting support */
|
||
iResult = hb_cdpcharcmp( c1, c2, cdpage );
|
||
#else
|
||
iResult = c1 - c2;
|
||
#endif
|
||
iPos++;
|
||
}
|
||
}
|
||
if ( iResult == 0 )
|
||
iResult = pKey1->realLength - pKey2->realLength;
|
||
}
|
||
else if ( iLimit == 0 || (iResult = memcmp( pKey1->Value, pKey2->Value, iLimit )) == 0 )
|
||
iResult = pKey1->length - pKey2->length;
|
||
if ( iResult < 0 )
|
||
return -1;
|
||
else if ( iResult > 0 )
|
||
return 1;
|
||
else
|
||
return 0;
|
||
}
|
||
|
||
static int hb_cdxSortKeyValCompare( LPCDXTAG pTag,
|
||
BYTE * pKeyVal1, BYTE keyLen1,
|
||
BYTE * pKeyVal2, BYTE keyLen2 )
|
||
{
|
||
CDXKEYINFO pKey1, pKey2;
|
||
pKey1.Value = pKeyVal1;
|
||
pKey1.length = keyLen1;
|
||
pKey2.Value = pKeyVal2;
|
||
pKey2.length = keyLen2;
|
||
pKey2.realLength = pKey1.realLength = pTag->uiLen;
|
||
pKey2.fString = pKey1.fString = ( pTag->uiType == 'C' );
|
||
#ifndef HB_CDP_SUPPORT_OFF
|
||
return hb_cdxSortKeyCompare( &pKey1, &pKey2, pTag->pIndex->pArea->cdPage );
|
||
#else
|
||
return hb_cdxSortKeyCompare( &pKey1, &pKey2 );
|
||
#endif
|
||
}
|
||
|
||
|
||
static void hb_cdxSortSwapSendWord( LPSORTINFO pSort, BYTE * Value )
|
||
{
|
||
LONG Tag;
|
||
BYTE bLen;
|
||
double d;
|
||
|
||
LPSORTSWAPITEM pItem;
|
||
|
||
bLen = Value[0];
|
||
bLen -= 8;
|
||
Value++;
|
||
HB_ORD2DBL( &Value[bLen], &d );
|
||
Tag = ( LONG ) d;
|
||
// hb_cdxSortOutputWord( pSort, Tag, Value, uiLen );
|
||
if ( pSort->pSwapPage->nCurPos + sizeof(SORTSWAPITEM) + bLen - 1 >= sizeof(pSort->pSwapPage->page) ) {
|
||
if ( hb_fsWrite( pSort->hTempFile, (BYTE *) pSort->pSwapPage->page, pSort->pSwapPage->nCurPos ) != pSort->pSwapPage->nCurPos )
|
||
{
|
||
hb_errInternal( 9999, "Create index: Write error in temporary file.", "", "" );
|
||
}
|
||
pSort->pSwapPage->pageLen += pSort->pSwapPage->nCurPos;
|
||
pSort->pSwapPage->nCurPos = 0;
|
||
}
|
||
|
||
pItem = (LPSORTSWAPITEM) (pSort->pSwapPage->page + pSort->pSwapPage->nCurPos);
|
||
pItem->recno = Tag;
|
||
pItem->keyLen = bLen;
|
||
memcpy( pItem->key, (char *) Value, bLen );
|
||
pSort->pSwapPage->nCurPos += sizeof(SORTSWAPITEM) + bLen - 1;
|
||
/*
|
||
typedef struct _SORTSWAPITEM
|
||
{
|
||
ULONG rec_no;
|
||
UCHAR keyLen;
|
||
char key[ 1 ];
|
||
} SORTSWAPITEM;
|
||
*/
|
||
}
|
||
|
||
static void hb_cdxSortSwapRecurseDict( LPSORTINFO pSort, LONG WPtr, LONG WBgn )
|
||
{
|
||
// USHORT WCnt;
|
||
BYTE WCnt;
|
||
|
||
if( WPtr == 0 )
|
||
return;
|
||
WCnt = pSort->WPch[ 0 ];
|
||
pSort->WAdr = hb_cdxSortLinkGet( pSort, WPtr );
|
||
pSort->WPch[ WCnt + 1 ] = pSort->WAdr->sortu.A.Character;
|
||
pSort->WPch[ 0 ]++;
|
||
if( SORT_GET_NUSE( pSort->WAdr->sortu.A.NUse ) == SORT_STACK_OF_CHAR )
|
||
{
|
||
memcpy( &pSort->WPch[ pSort->WPch[ 0 ] + 1 ],
|
||
pSort->WAdr->sortu.B.ChrStack, 4 );
|
||
pSort->WPch[ 0 ] += SORT_GET_STACK_LEN( pSort->WAdr->sortu.A.NUse ) + 1;
|
||
}
|
||
if( SORT_GET_NUSE(pSort->WAdr->sortu.A.NUse) == SORT_END_OF_WORD )
|
||
hb_cdxSortSwapSendWord( pSort, pSort->WPch );
|
||
else
|
||
{
|
||
if( pSort->WAdr->sortu.A.WordArray != 0 )
|
||
hb_cdxSortSwapRecurseDict( pSort, pSort->WAdr->sortu.A.WordArray, WBgn );
|
||
pSort->WAdr = hb_cdxSortLinkGet( pSort, WPtr );
|
||
}
|
||
pSort->WPch[ 0 ] = WCnt;
|
||
if( pSort->WAdr->sortu.A.LevelLink != 0 &&
|
||
SORT_GET_NUSE( pSort->WAdr->sortu.A.NUse) != SORT_STACK_OF_CHAR )
|
||
hb_cdxSortSwapRecurseDict( pSort, pSort->WAdr->sortu.A.LevelLink, WCnt );
|
||
}
|
||
|
||
static void hb_cdxSortSwapFillPage( LPSORTINFO pSort )
|
||
{
|
||
pSort->WPch[ 0 ] = 0;
|
||
hb_cdxSortSwapRecurseDict( pSort, pSort->RootLink, 0 );
|
||
}
|
||
|
||
static int hb_cdxSortSwapSavePage( LPSORTINFO pSort )
|
||
{
|
||
SORTSWAPPAGE swap;
|
||
BYTE *ptr;
|
||
pSort->nSwapPages++;
|
||
|
||
if ( ! pSort->hTempFile ) {
|
||
BYTE szName[ _POSIX_PATH_MAX + 1 ];
|
||
pSort->hTempFile = hb_fsCreateTemp( NULL, NULL, FC_NORMAL, szName );
|
||
if ( pSort->hTempFile == FS_ERROR ) {
|
||
hb_errInternal( 9999, "Create index: Can't create temporary file.", "", "" );
|
||
}
|
||
else {
|
||
pSort->szTempFileName = (char *) hb_xgrab( strlen( (char * ) szName) + 1 );
|
||
strcpy( pSort->szTempFileName, ( char * ) szName );
|
||
}
|
||
}
|
||
swap.nFileOffset = hb_fsSeek( pSort->hTempFile, 0, SEEK_END );
|
||
swap.mark[0] = 'C';
|
||
swap.mark[1] = 'X';
|
||
swap.pageNum = pSort->nSwapPages - 1;
|
||
swap.pageLen = 0;
|
||
swap.keyCount = pSort->WordCount;
|
||
swap.nCurPos = 0;
|
||
ptr = swap.page;
|
||
memcpy( ptr, swap.mark, 2 );
|
||
ptr += 2 * sizeof(char);
|
||
memcpy( ptr, (char *) &swap.pageNum, sizeof(swap.pageNum) );
|
||
ptr += sizeof(swap.pageNum);
|
||
memcpy( ptr, (char *) &swap.pageLen, sizeof(swap.pageLen) );
|
||
ptr += sizeof(swap.pageLen);
|
||
memcpy( ptr, (char *) &swap.keyCount, sizeof(swap.keyCount) );
|
||
// ptr += sizeof(ULONG);
|
||
swap.nCurPos += 2 * sizeof(char) + sizeof(USHORT) + 2 * sizeof(ULONG);
|
||
|
||
/*
|
||
if ( hb_fsWrite( pSort->hTempFile, (BYTE *) swap.page, swap.nCurPos ) != swap.nCurPos )
|
||
{
|
||
hb_errInternal( 9999, "Create index: Write error in temporary file.", "", "" );
|
||
}
|
||
*/
|
||
pSort->pSwapPage = &swap;
|
||
hb_cdxSortSwapFillPage( pSort );
|
||
pSort->pSwapPage = NULL;
|
||
|
||
if ( swap.nCurPos > 0 ) {
|
||
if ( hb_fsWrite( pSort->hTempFile, (BYTE *) swap.page, swap.nCurPos ) != swap.nCurPos )
|
||
{
|
||
hb_errInternal( 9999, "Create index: Write error in temporary file.", "", "" );
|
||
}
|
||
swap.pageLen += swap.nCurPos;
|
||
swap.nCurPos = 0;
|
||
}
|
||
hb_fsSeek( pSort->hTempFile, swap.nFileOffset + 2 * sizeof(char) + sizeof(swap.pageNum), SEEK_SET );
|
||
if ( hb_fsWrite( pSort->hTempFile, (BYTE *) &swap.pageLen, sizeof(swap.pageLen) ) != sizeof(ULONG) )
|
||
{
|
||
hb_errInternal( 9999, "Create index: Write error in temporary file.", "", "" );
|
||
}
|
||
|
||
/* Clear memory structures */
|
||
pSort->TotalWordCount += pSort->WordCount;
|
||
pSort->WordCount = 0;
|
||
//pSort->KeyCnt = 0; /* esto deber<65>a sacarlo */
|
||
if( pSort->ChunkList != NULL )
|
||
{
|
||
USHORT usCount;
|
||
for( usCount = 0; usCount < pSort->ChunkLimit; usCount++ )
|
||
{
|
||
if( pSort->ChunkList[ usCount ] != 0 )
|
||
memset( ( BYTE * ) pSort->ChunkList[ usCount ], 0, pSort->SortChunk * sizeof( BYTE ) );
|
||
}
|
||
}
|
||
// BYTE * SortBuffer; ???
|
||
pSort->ChunkCur = 0;
|
||
pSort->NodeCur = 1;
|
||
pSort->KeySize = 0;
|
||
// LPCDXDATA NodeList[ 32 ];
|
||
hb_cdxSortLinkNew( pSort, &pSort->RootLink );
|
||
|
||
return 0;
|
||
}
|
||
|
||
static BOOL hb_cdxSortSwapGetNextKey( LPSORTINFO pSort, LONG * pKeyRec, BYTE * pKeyVal,
|
||
USHORT * pKeyLen )
|
||
{
|
||
LPSORTSWAPPAGE pPage;
|
||
USHORT winPage, nPage;
|
||
ULONG winKeyRec;
|
||
BYTE winKeyLen;
|
||
BYTE * winKeyVal;
|
||
int iResult = 1;
|
||
|
||
/* this way some compilers don't emit warnings */
|
||
winPage = winKeyLen = 0;
|
||
winKeyRec = 0;
|
||
winKeyVal = NULL;
|
||
for ( nPage = 0 ; nPage < pSort->nSwapPages ; nPage++) {
|
||
pPage = pSort->pSwapPage + nPage;
|
||
if( pPage->keysLeft )
|
||
{
|
||
if( winKeyVal )
|
||
{
|
||
iResult = hb_cdxSortKeyValCompare( pSort->CurTag, winKeyVal, winKeyLen,
|
||
pPage->tmpKeyVal, pPage->tmpKeyLen );
|
||
}
|
||
if( iResult > 0 || ( iResult == 0 && pPage->tmpRecNo < winKeyRec ) )
|
||
{
|
||
winPage = nPage;
|
||
winKeyVal = pPage->tmpKeyVal;
|
||
winKeyLen = pPage->tmpKeyLen;
|
||
winKeyRec = pPage->tmpRecNo;
|
||
}
|
||
}
|
||
}
|
||
if( winKeyVal )
|
||
{
|
||
pPage = pSort->pSwapPage + winPage;
|
||
*pKeyRec = winKeyRec;
|
||
*pKeyLen = winKeyLen;
|
||
memcpy( pKeyVal, winKeyVal, winKeyLen);
|
||
|
||
if( --pPage->keysLeft )
|
||
{
|
||
LPSORTSWAPITEM pItem = NULL;
|
||
if ( pPage->nBufLeft < (USHORT) (sizeof(SORTSWAPITEM) + (USHORT) pPage->tmpKeyLen - 1) ) {
|
||
printf("Error! --- swapgetnextkey\n");
|
||
}
|
||
pPage->nCurPos += (sizeof(SORTSWAPITEM) + (USHORT) pPage->tmpKeyLen - 1);
|
||
pPage->nBufLeft -= (sizeof(SORTSWAPITEM) + (USHORT) pPage->tmpKeyLen - 1);
|
||
/* Debugging */
|
||
if ( pPage->nCurPos > 512 ) {
|
||
printf("Error! --- swapgetnextkey\n");
|
||
}
|
||
if ( pPage->nBufLeft > 512 ) {
|
||
printf("Error! --- swapgetnextkey\n");
|
||
}
|
||
if ( pPage->nBufLeft >= (sizeof(SORTSWAPITEM) - 1) ) {
|
||
pItem = (LPSORTSWAPITEM) (pPage->page + pPage->nCurPos);
|
||
if ( pPage->nBufLeft < (USHORT) (sizeof(SORTSWAPITEM) + (USHORT) pItem->keyLen - 1 ) )
|
||
pItem = NULL;
|
||
}
|
||
if ( !pItem ) {
|
||
pPage->nBytesLeft += pPage->nBufLeft;
|
||
hb_fsSeek( pSort->hTempFile, pPage->nFileOffset + pPage->pageLen - pPage->nBytesLeft, SEEK_SET );
|
||
pPage->nBufLeft = (USHORT) ( ( pPage->nBytesLeft < sizeof(pPage->page) ) ? pPage->nBytesLeft : sizeof(pPage->page) );
|
||
if ( hb_fsRead( pSort->hTempFile, (BYTE *) (pPage->page), pPage->nBufLeft ) != pPage->nBufLeft )
|
||
hb_errInternal( HB_EI_ERRUNRECOV, "hb_cdxTagDoIndex: Read error reading temporary index file", "hb_cdxTagDoIndex", NULL );
|
||
pPage->nBytesLeft -= pPage->nBufLeft;
|
||
pPage->nCurPos = 0;
|
||
pItem = (LPSORTSWAPITEM) (pPage->page);
|
||
}
|
||
pPage->tmpRecNo = pItem->recno;
|
||
pPage->tmpKeyLen = pItem->keyLen;
|
||
pPage->tmpKeyVal = ( BYTE * ) pItem->key;
|
||
}
|
||
return TRUE;
|
||
}
|
||
else
|
||
{
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
static int hb_cdxSortSwapBuildIndex( LPSORTINFO pSort )
|
||
{
|
||
LPSORTSWAPPAGE pPage;
|
||
LPSORTSWAPITEM pItem;
|
||
BYTE *ptr;
|
||
USHORT nPage;
|
||
LONG nKeyRec;
|
||
BYTE KeyVal[2][CDX_MAXKEY + 1], *pKeyVal, *pKeyPrevVal;
|
||
USHORT nKeyLen, nKeyPrevLen;
|
||
|
||
pSort->pSwapPage = (LPSORTSWAPPAGE) hb_xgrab( pSort->nSwapPages * sizeof( SORTSWAPPAGE ) );
|
||
if ( !pSort->pSwapPage )
|
||
hb_errInternal( HB_EI_ERRUNRECOV, "hb_cdxTagDoIndex: Not enough memory for index merging", "hb_cdxTagDoIndex", NULL );
|
||
|
||
hb_fsSeek( pSort->hTempFile, 0, SEEK_SET );
|
||
|
||
for ( nPage = 0 ; nPage < pSort->nSwapPages ; nPage++) {
|
||
pPage = pSort->pSwapPage + nPage;
|
||
pPage->nFileOffset = hb_fsSeek( pSort->hTempFile, 0, SEEK_CUR );
|
||
pPage->nBufLeft = 2 * sizeof(char) + sizeof(USHORT) + 2 * sizeof(ULONG);
|
||
if ( hb_fsRead( pSort->hTempFile, (BYTE *) (pPage->page), pPage->nBufLeft ) != pPage->nBufLeft )
|
||
hb_errInternal( HB_EI_ERRUNRECOV, "hb_cdxTagDoIndex: Read error reading temporary index file", "hb_cdxTagDoIndex", NULL );
|
||
ptr = pPage->page;
|
||
memcpy( pPage->mark, ptr, 2 );
|
||
ptr += 2 * sizeof(char);
|
||
memcpy( (char *) &pPage->pageNum, ptr, sizeof(pPage->pageNum) );
|
||
ptr += sizeof(pPage->pageNum);
|
||
memcpy( (char *) &pPage->pageLen, ptr, sizeof(pPage->pageLen) );
|
||
ptr += sizeof(pPage->pageLen);
|
||
memcpy( (char *) &pPage->keyCount, ptr, sizeof(pPage->keyCount) );
|
||
if ( memcmp( pPage->mark, "CX", 2 * sizeof(char) ) )
|
||
hb_errInternal( HB_EI_ERRUNRECOV, "hb_cdxTagDoIndex: Internal error 1", "hb_cdxTagDoIndex", NULL );
|
||
if ( pPage->pageNum != nPage )
|
||
hb_errInternal( HB_EI_ERRUNRECOV, "hb_cdxTagDoIndex: Internal error 2", "hb_cdxTagDoIndex", NULL );
|
||
//pPage->nCurPos ;
|
||
pPage->nBytesLeft = pPage->pageLen - pPage->nBufLeft;
|
||
pPage->keysLeft = pPage->keyCount;
|
||
|
||
pPage->nBufLeft = (USHORT) ( ( pPage->nBytesLeft < sizeof(pPage->page) ) ? pPage->nBytesLeft : sizeof(pPage->page) );
|
||
if ( hb_fsRead( pSort->hTempFile, (BYTE *) (pPage->page), pPage->nBufLeft ) != pPage->nBufLeft )
|
||
hb_errInternal( HB_EI_ERRUNRECOV, "hb_cdxTagDoIndex: Read error reading tempmrary index file", "hb_cdxTagDoIndex", NULL );
|
||
pPage->nBytesLeft -= pPage->nBufLeft;
|
||
pPage->nCurPos = 0;
|
||
|
||
pItem = (LPSORTSWAPITEM) (pPage->page);
|
||
pPage->tmpRecNo = pItem->recno;
|
||
pPage->tmpKeyLen = pItem->keyLen;
|
||
pPage->tmpKeyVal = ( BYTE * ) pItem->key;
|
||
|
||
hb_fsSeek( pSort->hTempFile, pPage->nFileOffset + pPage->pageLen, SEEK_SET );
|
||
#ifdef CDXDEBUG
|
||
printf("P<EFBFBD>gina %i, offset %x, largo %x : %i, claves: %i, bleft: %i\n",
|
||
pPage->pageNum, pPage->nFileOffset, pPage->pageLen, pPage->pageLen, pPage->keyCount, pPage->nBytesLeft);
|
||
#endif
|
||
}
|
||
|
||
pKeyVal = KeyVal[0];
|
||
pKeyPrevVal = NULL;
|
||
nKeyPrevLen = 0; /* init to avoid warnings */
|
||
while ( hb_cdxSortSwapGetNextKey( pSort, &nKeyRec, pKeyVal, &nKeyLen ) )
|
||
{
|
||
if ( pSort->Unique )
|
||
{
|
||
if ( pKeyPrevVal ) {
|
||
if ( nKeyPrevLen == nKeyLen ) {
|
||
if (! hb_cdxSortKeyValCompare( pSort->CurTag, pKeyPrevVal, (BYTE) nKeyPrevLen,
|
||
pKeyVal, (BYTE) nKeyLen ) )
|
||
{
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
pKeyPrevVal = pKeyVal;
|
||
nKeyPrevLen = nKeyLen;
|
||
hb_cdxSortOutputWord( pSort, nKeyRec, pKeyVal, nKeyLen );
|
||
if ( pKeyVal == KeyVal[0] )
|
||
{
|
||
pKeyVal = KeyVal[1];
|
||
}
|
||
else
|
||
{
|
||
pKeyVal = KeyVal[0];
|
||
}
|
||
}
|
||
else
|
||
{
|
||
hb_cdxSortOutputWord( pSort, nKeyRec, pKeyVal, nKeyLen );
|
||
}
|
||
}
|
||
|
||
/*
|
||
-------
|
||
hb_fsSeek( pSort->hTempFile, swap.nFileOffset + 2 * sizeof(char) + sizeof(ULONG), SEEK_SET );
|
||
*
|
||
*
|
||
*
|
||
// para grabar la clave...
|
||
hb_cdxSortOutputWord( pSort, Tag, Value, uiLen-8 );
|
||
*/
|
||
hb_xfree( pSort->pSwapPage );
|
||
pSort->pSwapPage = NULL;
|
||
return 0;
|
||
}
|
||
|
||
static LPSORTINFO hb_cdxSortNew( LPCDXTAG pTag, BOOL bUnique )
|
||
{
|
||
BYTE * P;
|
||
LPSORTINFO pSort;
|
||
|
||
pSort = ( LPSORTINFO ) hb_xgrab( sizeof( SORTINFO ) );
|
||
memset( pSort, 0, sizeof( SORTINFO ) );
|
||
pSort->SortChunk = SORT_CHUNK_LIMIT;
|
||
pSort->NodeLimit = pSort->SortChunk / sizeof( SORTDATA );
|
||
pSort->NodeMask = pSort->NodeShift = pSort->NodeCur = 1;
|
||
pSort->ChunkLimit = 0x8000;
|
||
while( pSort->NodeMask < pSort->NodeLimit - 1 )
|
||
{
|
||
pSort->NodeMask = ( pSort->NodeMask << 1 ) + 1;
|
||
pSort->ChunkLimit >>= 1;
|
||
pSort->NodeShift++;
|
||
}
|
||
pSort->ChunkSize = pSort->ChunkLimit;
|
||
pSort->ChunkList = ( LONG * ) hb_xgrab( pSort->ChunkSize * sizeof( LONG ) );
|
||
memset( pSort->ChunkList, 0, pSort->ChunkSize * sizeof( LONG ) );
|
||
P = ( BYTE * ) hb_xgrab( pSort->SortChunk * sizeof( BYTE ) );
|
||
memset( P, 0, pSort->SortChunk * sizeof( BYTE ) );
|
||
pSort->ChunkList[ 0 ] = ( LONG ) P;
|
||
hb_cdxSortLinkNew( pSort, &pSort->RootLink );
|
||
pSort->Unique = bUnique;
|
||
pSort->Ascend = TRUE;
|
||
pSort->CurTag = pTag;
|
||
pSort->KeyTot = pTag->pIndex->pArea->ulRecCount;
|
||
pSort->KeyWork = hb_cdxSortKeyNew();
|
||
pSort->LastKey = hb_cdxSortKeyNew();
|
||
return pSort;
|
||
}
|
||
|
||
static void hb_cdxSortPageWrite( LPCDXINDEX pIndex, ULONG ulPos, LPCDXDATA pPage )
|
||
{
|
||
/* it's a temporary hack */
|
||
#ifdef HB_BIG_ENDIAN
|
||
pPage->Node_Atr = HB_SWAP_USHORT( pPage->Node_Atr );
|
||
pPage->Rght_Ptr = HB_SWAP_ULONG ( pPage->Rght_Ptr );
|
||
pPage->Left_Ptr = HB_SWAP_ULONG ( pPage->Left_Ptr );
|
||
pPage->Entry_Ct = HB_SWAP_USHORT( pPage->Entry_Ct );
|
||
#endif
|
||
hb_cdxIndexPageWrite( pIndex, ulPos, (BYTE *) pPage, sizeof( CDXDATA ) );
|
||
#ifdef HB_BIG_ENDIAN
|
||
pPage->Node_Atr = HB_SWAP_USHORT( pPage->Node_Atr );
|
||
pPage->Rght_Ptr = HB_SWAP_ULONG ( pPage->Rght_Ptr );
|
||
pPage->Left_Ptr = HB_SWAP_ULONG ( pPage->Left_Ptr );
|
||
pPage->Entry_Ct = HB_SWAP_USHORT( pPage->Entry_Ct );
|
||
#endif
|
||
}
|
||
|
||
static void hb_cdxSortFree( LPSORTINFO pSort )
|
||
{
|
||
USHORT usCount;
|
||
LONG pa;
|
||
|
||
pSort->Closing = TRUE;
|
||
for( usCount = 0; usCount <= 30; usCount++ )
|
||
{
|
||
if( pSort->NodeList[ usCount ] != NULL )
|
||
{
|
||
pa = pSort->NodeList[ usCount ]->Rght_Ptr;
|
||
pSort->NodeList[ usCount ]->Rght_Ptr = CDX_DUMMYNODE;
|
||
if( pSort->NodeList[ usCount ]->Entry_Ct > 0 )
|
||
{
|
||
if( pSort->NodeList[ usCount + 1 ] == NULL )
|
||
{
|
||
pSort->CurTag->RootBlock = pa;
|
||
pSort->NodeList[ usCount ]->Node_Atr |= CDX_NODE_ROOT;
|
||
}
|
||
hb_cdxSortPageWrite( pSort->CurTag->pIndex, pa, pSort->NodeList[ usCount ] );
|
||
if( pSort->NodeList[ usCount + 1 ] != NULL )
|
||
hb_cdxSortAddToNode( pSort, ( USHORT ) ( usCount + 1 ), pa,
|
||
pSort->LastTag, pSort->KeyWork );
|
||
}
|
||
hb_xfree( ( LPCDXDATA ) pSort->NodeList[ usCount ] );
|
||
}
|
||
}
|
||
|
||
if( pSort->ChunkList != NULL )
|
||
{
|
||
for( usCount = 0; usCount < pSort->ChunkLimit; usCount++ )
|
||
{
|
||
if( pSort->ChunkList[ usCount ] != 0 )
|
||
hb_xfree( ( BYTE * ) pSort->ChunkList[ usCount ] );
|
||
}
|
||
hb_xfree( pSort->ChunkList );
|
||
}
|
||
hb_cdxSortKeyFree( pSort->KeyWork );
|
||
hb_cdxSortKeyFree( pSort->LastKey );
|
||
|
||
if ( pSort->hTempFile )
|
||
{
|
||
// hb_fsCommit( pSort->hTempFile );
|
||
hb_fsClose( pSort->hTempFile );
|
||
pSort->hTempFile = FS_ERROR;
|
||
}
|
||
if ( pSort->szTempFileName )
|
||
{
|
||
hb_fsDelete( (BYTE *) ( pSort->szTempFileName ) );
|
||
hb_xfree( pSort->szTempFileName );
|
||
pSort->szTempFileName = NULL;
|
||
}
|
||
|
||
hb_xfree( pSort );
|
||
}
|
||
|
||
static void hb_cdxSortLinkNew( LPSORTINFO pSort, LONG * NewLink )
|
||
{
|
||
if( pSort->NodeCur >= pSort->NodeLimit )
|
||
hb_cdxSortGetNewChunk( pSort );
|
||
* NewLink = ( pSort->ChunkCur << pSort->NodeShift ) + pSort->NodeCur;
|
||
pSort->NodeCur++;
|
||
}
|
||
|
||
static void hb_cdxSortGetNewChunk( LPSORTINFO pSort )
|
||
{
|
||
BYTE * P;
|
||
|
||
pSort->ChunkCur++;
|
||
if( pSort->ChunkCur == pSort->ChunkLimit )
|
||
{
|
||
hb_cdxSortSwapSavePage( pSort );
|
||
return;
|
||
}
|
||
P = ( BYTE * ) pSort->ChunkList[ pSort->ChunkCur ];
|
||
if( P == NULL )
|
||
P = ( BYTE * ) hb_xgrab( pSort->SortChunk * sizeof( BYTE ) );
|
||
if( pSort->ChunkCur != 0 )
|
||
{
|
||
memset( P, 0, pSort->SortChunk * sizeof( BYTE ) );
|
||
pSort->ChunkList[ pSort->ChunkCur ] = ( LONG ) P;
|
||
pSort->NodeCur = 0;
|
||
}
|
||
}
|
||
|
||
static void hb_cdxSortInsertWord( LPSORTINFO pSort, LONG Tag, char * Value,
|
||
USHORT uiLen )
|
||
{
|
||
char s[ 8 ];
|
||
double d;
|
||
USHORT cc, nc;
|
||
LPSORTDATA wx;
|
||
|
||
d = ( double ) Tag;
|
||
HB_DBL2ORD( &d, s );
|
||
|
||
if( pSort->NodeLimit - pSort->NodeCur < uiLen + 8 )
|
||
{
|
||
cc = pSort->ChunkCur;
|
||
nc = pSort->NodeCur;
|
||
hb_cdxSortGetNewChunk( pSort );
|
||
if( pSort->ChunkCur > 0 )
|
||
{
|
||
pSort->ChunkCur = cc;
|
||
pSort->NodeCur = nc;
|
||
}
|
||
}
|
||
pSort->WordCount++;
|
||
memcpy( pSort->WPch+1, Value, uiLen );
|
||
pSort->WPch[0] = (BYTE) uiLen;
|
||
|
||
if( pSort->WPch[0] > pSort->KeySize )
|
||
pSort->KeySize = pSort->WPch[0];
|
||
pSort->LevelPtr = pSort->RootLink;
|
||
pSort->PriorPtr = 0;
|
||
pSort->WCur = 0;
|
||
do
|
||
hb_cdxSortStuffKey( pSort, &wx, FALSE );
|
||
while( pSort->WCur != pSort->WPch[0] );
|
||
if( pSort->Unique )
|
||
{
|
||
if( SORT_GET_NUSE(wx->sortu.A.NUse) == SORT_END_OF_KEY )
|
||
{
|
||
pSort->WordCount--;
|
||
return;
|
||
}
|
||
SORT_SET_NUSE( wx->sortu.A.NUse, SORT_END_OF_KEY);
|
||
}
|
||
|
||
memcpy( &pSort->WPch[ pSort->WPch[0] + 1 ], s, 8 );
|
||
pSort->WPch[0] += 8;
|
||
do
|
||
hb_cdxSortStuffKey( pSort, &wx, TRUE );
|
||
while( pSort->WCur != pSort->WPch[0] );
|
||
|
||
SORT_SET_NUSE(wx->sortu.A.NUse, SORT_END_OF_WORD);
|
||
}
|
||
|
||
static void hb_cdxSortStuffKey( LPSORTINFO pSort, LPSORTDATA * wx, BOOL fTag )
|
||
{
|
||
SHORT v;
|
||
LONG p1;
|
||
LPSORTDATA x;
|
||
|
||
hb_cdxSortGetNode( pSort, pSort->WPch[ pSort->WCur + 1 ], &p1, fTag );
|
||
* wx = hb_cdxSortLinkGet( pSort, p1 );
|
||
pSort->WCur++;
|
||
if( pSort->LevelPtr == 0 )
|
||
{
|
||
if( pSort->PriorPtr > 0 )
|
||
{
|
||
x = hb_cdxSortLinkGet( pSort, pSort->PriorPtr );
|
||
x->sortu.A.WordArray = (USHORT) p1;
|
||
}
|
||
v = pSort->WPch[0] - pSort->WCur - 1;
|
||
if( v > 0 )
|
||
{
|
||
if( v > 4 )
|
||
v = 4;
|
||
memcpy( ( * wx )->sortu.B.ChrStack, &pSort->WPch[ pSort->WCur+1 ], v );
|
||
SORT_SET_NUSE( ( * wx )->sortu.A.NUse, SORT_STACK_OF_CHAR );
|
||
SORT_SET_STACK_LEN( ( * wx )->sortu.A.NUse, v-1 );
|
||
pSort->WCur += v;
|
||
}
|
||
}
|
||
pSort->PriorPtr = p1;
|
||
pSort->LevelPtr = ( * wx )->sortu.A.WordArray;
|
||
}
|
||
|
||
static void hb_cdxSortGetNode( LPSORTINFO pSort, BYTE Character, LONG * NewLink, BOOL fTag )
|
||
{
|
||
char c;
|
||
int df;
|
||
LONG p, q, r;
|
||
LPSORTDATA px, qx, rx;
|
||
#ifndef HB_CDP_SUPPORT_OFF
|
||
PHB_CODEPAGE cdPage = pSort->CurTag->pIndex->pArea->cdPage;
|
||
#endif
|
||
|
||
if( pSort->LevelPtr == 0 )
|
||
{
|
||
hb_cdxSortLinkNew( pSort, NewLink );
|
||
px = hb_cdxSortLinkGet( pSort, * NewLink );
|
||
px->sortu.A.Character = Character;
|
||
if( fTag )
|
||
px->sortu.A.NUse |= SORT_NOT_KEY;
|
||
return;
|
||
}
|
||
p = pSort->LevelPtr;
|
||
px = hb_cdxSortLinkGet( pSort, pSort->LevelPtr );
|
||
q = pSort->PriorPtr;
|
||
|
||
if( SORT_GET_NUSE(px->sortu.A.NUse) == SORT_STACK_OF_CHAR )
|
||
{
|
||
hb_cdxSortLinkNew( pSort, &r );
|
||
c = px->sortu.A.Character;
|
||
qx = hb_cdxSortLinkGet( pSort, q );
|
||
qx->sortu.A.WordArray = (USHORT) r;
|
||
rx = hb_cdxSortLinkGet( pSort, r );
|
||
rx->sortu.A.Character = c;
|
||
rx->sortu.A.WordArray = (USHORT) p;
|
||
px = hb_cdxSortLinkGet( pSort, p );
|
||
px->sortu.A.Character = px->sortu.B.ChrStack[ 0 ];
|
||
memmove( &px->sortu.B.ChrStack[ 0 ], &px->sortu.B.ChrStack[ 1 ], 3 );
|
||
px->sortu.B.ChrStack[ 3 ] = 0;
|
||
if( px->sortu.A.NUse & SORT_NOT_KEY )
|
||
rx->sortu.A.NUse |= SORT_NOT_KEY;
|
||
if( SORT_GET_STACK_LEN( px->sortu.A.NUse ) )
|
||
{
|
||
SORT_SET_STACK_LEN( px->sortu.A.NUse,
|
||
SORT_GET_STACK_LEN( px->sortu.A.NUse ) - 1 );
|
||
SORT_SET_NUSE( px->sortu.A.NUse, SORT_STACK_OF_CHAR );
|
||
}
|
||
else
|
||
SORT_SET_NUSE( px->sortu.A.NUse, SORT_ACTIVE_LIST );
|
||
|
||
p = r;
|
||
px = hb_cdxSortLinkGet( pSort, p );
|
||
}
|
||
|
||
if( pSort->CurTag->uiType == 'C' && ( !( px->sortu.A.NUse & SORT_NOT_KEY ) || !fTag ) )
|
||
#ifndef HB_CDP_SUPPORT_OFF
|
||
/* for nation sorting support */
|
||
df = hb_cdpcharcmp( fTag ? ' ' : Character, ( px->sortu.A.NUse & SORT_NOT_KEY ) ? ' ' : px->sortu.A.Character, cdPage );
|
||
#else
|
||
df = ( fTag ? ' ' : Character ) - ( ( px->sortu.A.NUse & SORT_NOT_KEY ) ? ' ' : px->sortu.A.Character );
|
||
#endif
|
||
else if( ( px->sortu.A.NUse & SORT_NOT_KEY ) && !fTag )
|
||
df = 1;
|
||
else if( fTag && !( px->sortu.A.NUse & SORT_NOT_KEY ) )
|
||
df = -1;
|
||
else if( Character > px->sortu.A.Character )
|
||
df = 1;
|
||
else if( Character < px->sortu.A.Character )
|
||
df = -1;
|
||
else
|
||
df = 0;
|
||
|
||
if( !pSort->Ascend )
|
||
df = -df;
|
||
|
||
while( px->sortu.A.LevelLink != 0 && df > 0 )
|
||
{
|
||
q = p;
|
||
p = px->sortu.A.LevelLink;
|
||
px = hb_cdxSortLinkGet( pSort, p );
|
||
|
||
if( SORT_GET_NUSE(px->sortu.A.NUse) == SORT_STACK_OF_CHAR )
|
||
{
|
||
hb_cdxSortLinkNew( pSort, &r );
|
||
c = px->sortu.A.Character;
|
||
qx = hb_cdxSortLinkGet( pSort, q );
|
||
qx->sortu.A.WordArray = (USHORT) r;
|
||
rx = hb_cdxSortLinkGet( pSort, r );
|
||
rx->sortu.A.Character = c;
|
||
rx->sortu.A.WordArray = (USHORT) p;
|
||
px = hb_cdxSortLinkGet( pSort, p );
|
||
px->sortu.A.Character = px->sortu.B.ChrStack[ 0 ];
|
||
memmove( &px->sortu.B.ChrStack[ 0 ], &px->sortu.B.ChrStack[ 1 ], 3 );
|
||
px->sortu.B.ChrStack[ 3 ] = 0;
|
||
if( px->sortu.A.NUse & SORT_NOT_KEY )
|
||
rx->sortu.A.NUse |= SORT_NOT_KEY;
|
||
if( SORT_GET_STACK_LEN( px->sortu.A.NUse ) )
|
||
{
|
||
SORT_SET_STACK_LEN( px->sortu.A.NUse,
|
||
SORT_GET_STACK_LEN( px->sortu.A.NUse ) - 1 );
|
||
SORT_SET_NUSE( px->sortu.A.NUse, SORT_STACK_OF_CHAR );
|
||
}
|
||
else
|
||
SORT_SET_NUSE( px->sortu.A.NUse, SORT_ACTIVE_LIST );
|
||
p = r;
|
||
px = hb_cdxSortLinkGet( pSort, p );
|
||
}
|
||
|
||
if( pSort->CurTag->uiType == 'C' && ( !( px->sortu.A.NUse & SORT_NOT_KEY ) || !fTag ) )
|
||
#ifndef HB_CDP_SUPPORT_OFF
|
||
/* for nation sorting support */
|
||
df = hb_cdpcharcmp( fTag ? ' ' : Character, ( px->sortu.A.NUse & SORT_NOT_KEY ) ? ' ' : px->sortu.A.Character, cdPage );
|
||
#else
|
||
df = ( fTag ? ' ' : Character ) - ( ( px->sortu.A.NUse & SORT_NOT_KEY ) ? ' ' : px->sortu.A.Character );
|
||
#endif
|
||
else if( (px->sortu.A.NUse & SORT_NOT_KEY) && !fTag)
|
||
df = 1;
|
||
else if( fTag && !( px->sortu.A.NUse & SORT_NOT_KEY ) )
|
||
df = -1;
|
||
else if( Character > px->sortu.A.Character )
|
||
df = 1;
|
||
else if( Character < px->sortu.A.Character )
|
||
df = -1;
|
||
else
|
||
df = 0;
|
||
|
||
if( !pSort->Ascend )
|
||
df = -df;
|
||
}
|
||
|
||
if( df == 0 )
|
||
* NewLink = p;
|
||
else
|
||
{
|
||
hb_cdxSortLinkNew( pSort, &r );
|
||
if( df < 0 )
|
||
{
|
||
qx = hb_cdxSortLinkGet( pSort, q );
|
||
if( q == pSort->PriorPtr )
|
||
qx->sortu.A.WordArray = (USHORT) r;
|
||
else
|
||
qx->sortu.A.LevelLink = (USHORT) r;
|
||
}
|
||
else
|
||
{
|
||
p = px->sortu.A.LevelLink;
|
||
px->sortu.A.LevelLink = (USHORT) r;
|
||
}
|
||
rx = hb_cdxSortLinkGet( pSort, r );
|
||
rx->sortu.A.LevelLink = (USHORT) p;
|
||
rx->sortu.A.Character = Character;
|
||
if( fTag )
|
||
rx->sortu.A.NUse |= SORT_NOT_KEY;
|
||
* NewLink = r;
|
||
}
|
||
}
|
||
|
||
static LPSORTDATA hb_cdxSortLinkGet( LPSORTINFO pSort, LONG Value )
|
||
{
|
||
LPSORTDATA P;
|
||
|
||
if( Value > 0 )
|
||
{
|
||
P = ( LPSORTDATA ) pSort->ChunkList[ Value >> pSort->NodeShift ];
|
||
if( P != NULL )
|
||
return &P[ Value & pSort->NodeMask ];
|
||
else
|
||
return NULL;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
static void hb_cdxSortDisplayWord( LPSORTINFO pSort )
|
||
{
|
||
// esto hay que cambiarlo, est<73> para prueba TODO
|
||
if ( pSort->nSwapPages ) {
|
||
if ( pSort->WordCount )
|
||
hb_cdxSortSwapSavePage( pSort );
|
||
hb_cdxSortSwapBuildIndex( pSort );
|
||
}
|
||
else
|
||
{
|
||
pSort->TotalWordCount = pSort->WordCount;
|
||
pSort->WPch[ 0 ] = 0;
|
||
hb_cdxSortRecurseDict( pSort, pSort->RootLink, 0 );
|
||
}
|
||
}
|
||
|
||
static void hb_cdxSortRecurseDict( LPSORTINFO pSort, LONG WPtr, LONG WBgn )
|
||
{
|
||
// USHORT WCnt;
|
||
BYTE WCnt;
|
||
|
||
if( WPtr == 0 )
|
||
return;
|
||
WCnt = pSort->WPch[ 0 ];
|
||
pSort->WAdr = hb_cdxSortLinkGet( pSort, WPtr );
|
||
pSort->WPch[ WCnt + 1 ] = pSort->WAdr->sortu.A.Character;
|
||
pSort->WPch[ 0 ]++;
|
||
if( SORT_GET_NUSE( pSort->WAdr->sortu.A.NUse ) == SORT_STACK_OF_CHAR )
|
||
{
|
||
memcpy( &pSort->WPch[ pSort->WPch[ 0 ] + 1 ],
|
||
pSort->WAdr->sortu.B.ChrStack, 4 );
|
||
pSort->WPch[ 0 ] += SORT_GET_STACK_LEN( pSort->WAdr->sortu.A.NUse ) + 1;
|
||
}
|
||
if( SORT_GET_NUSE(pSort->WAdr->sortu.A.NUse) == SORT_END_OF_WORD )
|
||
hb_cdxSortSendWord( pSort, pSort->WPch );
|
||
else
|
||
{
|
||
if( pSort->WAdr->sortu.A.WordArray != 0 )
|
||
hb_cdxSortRecurseDict( pSort, pSort->WAdr->sortu.A.WordArray, WBgn );
|
||
pSort->WAdr = hb_cdxSortLinkGet( pSort, WPtr );
|
||
}
|
||
pSort->WPch[ 0 ] = WCnt;
|
||
if( pSort->WAdr->sortu.A.LevelLink != 0 &&
|
||
SORT_GET_NUSE( pSort->WAdr->sortu.A.NUse) != SORT_STACK_OF_CHAR )
|
||
hb_cdxSortRecurseDict( pSort, pSort->WAdr->sortu.A.LevelLink, WCnt );
|
||
}
|
||
|
||
static void hb_cdxSortSendWord( LPSORTINFO pSort, BYTE * Value )
|
||
{
|
||
LONG Tag;
|
||
USHORT uiLen;
|
||
double d;
|
||
|
||
uiLen = ( USHORT ) Value[0];
|
||
Value++;
|
||
HB_ORD2DBL( &Value[uiLen - 8], &d );
|
||
Tag = ( LONG ) d;
|
||
hb_cdxSortOutputWord( pSort, Tag, Value, uiLen - 8 );
|
||
}
|
||
|
||
static void hb_cdxSortOutputWord( LPSORTINFO pSort, LONG Tag, BYTE * Value,
|
||
USHORT uiLen )
|
||
{
|
||
pSort->KeyCnt++;
|
||
/*
|
||
Patch for empty fields
|
||
*/
|
||
while( uiLen > 0 && Value[uiLen-1] ==
|
||
( pSort->CurTag->uiType == 'C' ? ' ' : 0 ) )
|
||
{
|
||
uiLen--;
|
||
}
|
||
hb_cdxSortKeyPut( pSort->KeyWork, Value, uiLen,
|
||
pSort->CurTag->uiLen, ( pSort->CurTag->uiType == 'C' ) );
|
||
hb_cdxSortAddToNode( pSort, 0, Tag, Tag, pSort->KeyWork );
|
||
pSort->LastTag = Tag;
|
||
hb_cdxSortKeyCopy( pSort->LastKey, pSort->KeyWork );
|
||
}
|
||
|
||
static void hb_cdxSortAddToNode( LPSORTINFO pSort, USHORT Lvl, LONG Tag,
|
||
LONG Link, LPCDXKEYINFO Value )
|
||
{
|
||
USHORT i, bitcnt;
|
||
LONG sr, mask;
|
||
|
||
if( pSort->NodeList[ Lvl ] == NULL )
|
||
{
|
||
pSort->NodeList[ Lvl ] = ( LPCDXDATA ) hb_xgrab( sizeof( CDXDATA ) );
|
||
memset( pSort->NodeList[ Lvl ], 0, sizeof( CDXDATA ) );
|
||
if( Lvl == 0 )
|
||
{
|
||
sr = pSort->KeyTot;
|
||
i = pSort->CurTag->uiLen;
|
||
for( bitcnt = 0; i; bitcnt++, i >>= 1 );
|
||
pSort->NodeList[ 0 ]->cdxu.External.ShortBytes = 3;
|
||
pSort->NodeList[ 0 ]->cdxu.External.RecNumBits = 24 - bitcnt * 2;
|
||
mask = HB_CDXBITMASK( pSort->NodeList[ 0 ]->cdxu.External.RecNumBits );
|
||
while ( sr > mask )
|
||
{
|
||
pSort->NodeList[ 0 ]->cdxu.External.ShortBytes++;
|
||
pSort->NodeList[ 0 ]->cdxu.External.RecNumBits += 8;
|
||
mask = mask << 8 | 0xFF;
|
||
}
|
||
HB_PUT_LE_ULONG( pSort->NodeList[ 0 ]->cdxu.External.RecNumMask, mask );
|
||
HB_PUT_LE_USHORT( pSort->NodeList[ 0 ]->cdxu.External.FreeSpace, CDX_EXTERNAL_SPACE );
|
||
pSort->NodeList[ 0 ]->cdxu.External.DupCntBits =
|
||
pSort->NodeList[ 0 ]->cdxu.External.TrlCntBits = (BYTE) bitcnt;
|
||
pSort->NodeList[ 0 ]->cdxu.External.DupCntMask =
|
||
(BYTE) HB_CDXBITMASK( pSort->NodeList[ 0 ]->cdxu.External.DupCntBits );
|
||
pSort->NodeList[ 0 ]->cdxu.External.TrlCntMask =
|
||
(BYTE) HB_CDXBITMASK( pSort->NodeList[ 0 ]->cdxu.External.TrlCntBits );
|
||
}
|
||
pSort->NodeList[ Lvl ]->Left_Ptr = CDX_DUMMYNODE;
|
||
pSort->NodeList[ Lvl ]->Rght_Ptr = hb_cdxIndexGetAvailPage( pSort->CurTag->pIndex, FALSE );
|
||
pSort->NodeList[ Lvl ]->Node_Atr = ( Lvl == 0 ) ? CDX_NODE_LEAF : CDX_NODE_BRANCH;
|
||
}
|
||
if( Lvl == 0 )
|
||
hb_cdxSortAddExternal( pSort, Lvl, Tag, Link, Value );
|
||
else
|
||
hb_cdxSortAddInternal( pSort, Lvl, Tag, Link, Value );
|
||
}
|
||
|
||
static void hb_cdxSortAddExternal( LPSORTINFO pSort, USHORT Lvl, LONG Tag, LONG Link,
|
||
LPCDXKEYINFO Value )
|
||
{
|
||
USHORT k, ct, cd, v, c;
|
||
LONG pa;
|
||
|
||
if( pSort->NodeList[ Lvl ]->Entry_Ct == 0 )
|
||
{
|
||
memset( pSort->NodeList[ Lvl ]->cdxu.External.ExtData, 0,
|
||
sizeof( pSort->NodeList[ Lvl ]->cdxu.External.ExtData ) );
|
||
HB_PUT_LE_USHORT( pSort->NodeList[ Lvl ]->cdxu.External.FreeSpace, CDX_EXTERNAL_SPACE );
|
||
|
||
hb_cdxSortKeyPut( pSort->LastKey, (BYTE*) "", 0, 0, ( pSort->CurTag->uiType == 'C' ) );
|
||
}
|
||
ct = ( USHORT ) ( pSort->CurTag->uiLen - Value->length );
|
||
cd = hb_cdxSortKeyFindDup( Value, pSort->LastKey );
|
||
|
||
#ifdef HB_CDX_DBGCODE_EXT
|
||
#ifndef HB_CDP_SUPPORT_OFF
|
||
if( hb_cdxSortKeyCompare( Value, pSort->LastKey, pSort->CurTag->pIndex->pArea->cdPage ) < 0 )
|
||
#else
|
||
if( hb_cdxSortKeyCompare( Value, pSort->LastKey ) < 0 )
|
||
#endif
|
||
{
|
||
/*
|
||
printf("\r\nValue->length=%2d, Value->Value=%s", Value->length, Value->Value);
|
||
printf("\r\n Last->length=%2d, Last->Value=%s", pSort->LastKey->length, pSort->LastKey->Value);
|
||
fflush(stdout);
|
||
*/
|
||
hb_cdxErrInternal( "hb_cdxSortAddExternal: Index corrupted" );
|
||
}
|
||
#endif
|
||
v = ( USHORT ) ( pSort->NodeList[ Lvl ]->Entry_Ct *
|
||
pSort->NodeList[ Lvl ]->cdxu.External.ShortBytes );
|
||
k = HB_GET_LE_USHORT( pSort->NodeList[ Lvl ]->cdxu.External.FreeSpace );
|
||
c = k - ( USHORT ) ( pSort->CurTag->uiLen +
|
||
pSort->NodeList[ Lvl ]->cdxu.External.ShortBytes -
|
||
cd - ct );
|
||
HB_PUT_LE_USHORT( pSort->NodeList[ Lvl ]->cdxu.External.FreeSpace, c );
|
||
k += v;
|
||
/*
|
||
// RECMASK
|
||
rr = ( (ULONGLONG) ct << ( ( pSort->NodeList[ Lvl ]->cdxu.External.ShortBytes * 8 ) -
|
||
pSort->NodeList[ Lvl ]->cdxu.External.TrlCntBits ) ) |
|
||
( (ULONGLONG) cd << ( ( pSort->NodeList[ Lvl ]->cdxu.External.ShortBytes * 8 ) -
|
||
pSort->NodeList[ Lvl ]->cdxu.External.TrlCntBits -
|
||
pSort->NodeList[ Lvl ]->cdxu.External.DupCntBits ) ) |
|
||
Tag;
|
||
memcpy( &pSort->NodeList[ Lvl ]->cdxu.External.ExtData[ v ], &rr, pSort->NodeList[ Lvl ]->cdxu.External.ShortBytes );
|
||
*/
|
||
hb_cdxSetLeafRecord( &pSort->NodeList[ Lvl ]->cdxu.External.ExtData[ v ],
|
||
Tag, cd, ct,
|
||
pSort->NodeList[ Lvl ]->cdxu.External.ShortBytes,
|
||
pSort->NodeList[ Lvl ]->cdxu.External.DupCntBits,
|
||
pSort->NodeList[ Lvl ]->cdxu.External.TrlCntBits );
|
||
k -= ( USHORT ) ( pSort->CurTag->uiLen - cd - ct );
|
||
if( pSort->CurTag->uiLen - cd - ct > 0 )
|
||
memcpy( &pSort->NodeList[ Lvl ]->cdxu.External.ExtData[ k ],
|
||
Value->Value + cd,
|
||
pSort->CurTag->uiLen - cd - ct );
|
||
pSort->NodeList[ Lvl ]->Entry_Ct++;
|
||
if( HB_GET_LE_USHORT( pSort->NodeList[ Lvl ]->cdxu.External.FreeSpace ) <
|
||
( pSort->CurTag->uiLen +
|
||
pSort->NodeList[ Lvl ]->cdxu.External.ShortBytes ) * 1 ) /* 2 only if count after the key was added */
|
||
{
|
||
pa = pSort->NodeList[ Lvl ]->Rght_Ptr;
|
||
// TODO : check this, may be wrong
|
||
/* if( pSort->KeyCnt < pSort->KeyTot ) */
|
||
if( pSort->KeyCnt < pSort->TotalWordCount )
|
||
pSort->NodeList[ Lvl ]->Rght_Ptr = hb_cdxIndexGetAvailPage( pSort->CurTag->pIndex, FALSE );
|
||
else
|
||
pSort->NodeList[ Lvl ]->Rght_Ptr = CDX_DUMMYNODE;
|
||
pSort->NodeList[ Lvl ]->Node_Atr = CDX_NODE_LEAF;
|
||
hb_cdxSortPageWrite( pSort->CurTag->pIndex, pa, pSort->NodeList[ Lvl ] );
|
||
pSort->NodeList[ Lvl ]->Left_Ptr = pa;
|
||
hb_cdxSortAddToNode( pSort, ( USHORT ) ( Lvl + 1 ), pa, Link, Value );
|
||
pSort->NodeList[ Lvl ]->Entry_Ct = 0;
|
||
}
|
||
}
|
||
|
||
static void hb_cdxSortAddInternal( LPSORTINFO pSort, USHORT Lvl, LONG Tag, LONG Link,
|
||
LPCDXKEYINFO Value )
|
||
{
|
||
USHORT v;
|
||
LONG pa;
|
||
|
||
if( pSort->NodeList[ Lvl ]->Entry_Ct == 0 )
|
||
memset( pSort->NodeList[ Lvl ]->cdxu.Internal.IntData,
|
||
pSort->CurTag->uiType == 'C' ? 32 : 0,
|
||
sizeof( pSort->NodeList[ Lvl ]->cdxu.Internal.IntData ) );
|
||
v = ( USHORT ) ( pSort->NodeList[ Lvl ]->Entry_Ct *
|
||
( pSort->CurTag->uiLen + 8 ) );
|
||
memcpy( &pSort->NodeList[ Lvl ]->cdxu.Internal.IntData[ v ],
|
||
Value->Value, Value->length );
|
||
v += pSort->CurTag->uiLen;
|
||
HB_PUT_BE_ULONG( &pSort->NodeList[ Lvl ]->cdxu.Internal.IntData[ v ], Link );
|
||
HB_PUT_BE_ULONG( &pSort->NodeList[ Lvl ]->cdxu.Internal.IntData[ v + 4 ], Tag );
|
||
pSort->NodeList[ Lvl ]->Entry_Ct++;
|
||
if( pSort->NodeList[ Lvl ]->Entry_Ct >= pSort->CurTag->MaxKeys )
|
||
{
|
||
pa = pSort->NodeList[ Lvl ]->Rght_Ptr;
|
||
if( !pSort->Closing )
|
||
pSort->NodeList[ Lvl ]->Rght_Ptr = hb_cdxIndexGetAvailPage( pSort->CurTag->pIndex, FALSE );
|
||
else
|
||
pSort->NodeList[ Lvl ]->Rght_Ptr = CDX_DUMMYNODE;
|
||
pSort->NodeList[ Lvl ]->Node_Atr = CDX_NODE_BRANCH;
|
||
hb_cdxSortPageWrite( pSort->CurTag->pIndex, pa, pSort->NodeList[ Lvl ] );
|
||
pSort->NodeList[ Lvl ]->Left_Ptr = pa;
|
||
hb_cdxSortAddToNode( pSort, ( USHORT ) ( Lvl + 1 ), pa, Link, Value );
|
||
pSort->NodeList[ Lvl ]->Entry_Ct = 0;
|
||
}
|
||
}
|
||
|
||
/* ######################################################################### */
|
||
|
||
static void hb_cdxTagEmptyIndex( LPCDXTAG pTag )
|
||
{
|
||
pTag->RootPage = hb_cdxPageNew( pTag, NULL, 0 );
|
||
pTag->RootBlock = pTag->RootPage->Page;
|
||
pTag->RootPage->PageType = CDX_NODE_ROOT | CDX_NODE_LEAF;
|
||
hb_cdxPageLeafInitSpace( pTag->RootPage );
|
||
}
|
||
|
||
static void hb_cdxTagDoIndex( LPCDXTAG pTag )
|
||
{
|
||
ULONG ulRecNo, ulRecCount;
|
||
BOOL bForOk;
|
||
LPSORTINFO pSort;
|
||
PHB_ITEM pItem;
|
||
HB_MACRO_PTR pMacro;
|
||
BYTE cTemp[8];
|
||
LPCDXAREA pArea = pTag->pIndex->pArea;
|
||
LONG lStep = 0;
|
||
BOOL bDirectRead, bEnd;
|
||
PHB_ITEM pForItem, pWhileItem, pEvalItem;
|
||
#ifndef HB_CDP_SUPPORT_OFF
|
||
/* TODO: this hack is not thread safe, s_cdpage has to be thread specific */
|
||
PHB_CODEPAGE cdpTmp = s_cdpage;
|
||
s_cdpage = pArea->cdPage;
|
||
#endif
|
||
|
||
if ( ( pTag->OptFlags & CDX_TYPE_STRUCTURE ) || pTag->Custom )
|
||
{
|
||
hb_cdxTagEmptyIndex( pTag );
|
||
}
|
||
else
|
||
{
|
||
BOOL bSaveDeleted = hb_set.HB_SET_DELETED;
|
||
PHB_ITEM pSaveFilter = pArea->dbfi.itmCobExpr;
|
||
USHORT uiSaveTag = pArea->uiTag;
|
||
hb_set.HB_SET_DELETED = FALSE;
|
||
pArea->dbfi.itmCobExpr = NULL;
|
||
|
||
pSort = hb_cdxSortNew( pTag, pTag->UniqueKey );
|
||
pItem = hb_itemNew( NULL );
|
||
ulRecCount = pArea->ulRecCount;
|
||
pForItem = pTag->pForItem;
|
||
bForOk = TRUE;
|
||
pEvalItem = ( pArea->lpdbOrdCondInfo ? pArea->lpdbOrdCondInfo->itmCobEval : NULL);
|
||
pWhileItem = ( pArea->lpdbOrdCondInfo ? pArea->lpdbOrdCondInfo->itmCobWhile : NULL);
|
||
bEnd = FALSE;
|
||
bDirectRead = !hb_set.HB_SET_STRICTREAD && !pArea->lpdbRelations &&
|
||
( !pArea->lpdbOrdCondInfo || pArea->lpdbOrdCondInfo->fAll );
|
||
if ( !bDirectRead )
|
||
{
|
||
if ( !pArea->lpdbOrdCondInfo || pArea->lpdbOrdCondInfo->fAll )
|
||
{
|
||
pArea->uiTag = 0;
|
||
SELF_GOTOP( ( AREAP ) pArea );
|
||
}
|
||
else if ( pArea->lpdbOrdCondInfo->lRecno )
|
||
{
|
||
SELF_GOTO( ( AREAP ) pArea, pArea->lpdbOrdCondInfo->lRecno );
|
||
bEnd = TRUE;
|
||
}
|
||
else if ( pArea->lpdbOrdCondInfo->fUseCurrent )
|
||
{
|
||
if ( pArea->lpdbOrdCondInfo->lStartRecno )
|
||
{
|
||
SELF_GOTO( ( AREAP ) pArea, pArea->lpdbOrdCondInfo->lStartRecno );
|
||
}
|
||
else
|
||
{
|
||
SELF_GOTOP( ( AREAP ) pArea );
|
||
}
|
||
}
|
||
else if ( pArea->lpdbOrdCondInfo->fRest || pArea->lpdbOrdCondInfo->lNextCount )
|
||
{
|
||
if ( pArea->lpdbOrdCondInfo->lStartRecno )
|
||
{
|
||
SELF_GOTO( ( AREAP ) pArea, pArea->lpdbOrdCondInfo->lStartRecno );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pArea->uiTag = 0;
|
||
SELF_GOTOP( ( AREAP ) pArea );
|
||
}
|
||
}
|
||
for ( ulRecNo = 1; ulRecNo <= ulRecCount; ulRecNo++ )
|
||
{
|
||
if ( bDirectRead )
|
||
{
|
||
hb_fsSeek( pArea->hDataFile,
|
||
pArea->uiHeaderLen + ( ulRecNo - 1 ) * pArea->uiRecordLen,
|
||
FS_SET );
|
||
hb_fsRead( pArea->hDataFile, pArea->pRecord, pArea->uiRecordLen );
|
||
pArea->ulRecNo = ulRecNo;
|
||
pArea->fDeleted = ( pArea->pRecord[ 0 ] == '*' );
|
||
}
|
||
else if ( pWhileItem && !hb_cdxEvalCond ( NULL, pWhileItem, FALSE ) )
|
||
break;
|
||
|
||
if ( pForItem != NULL )
|
||
{
|
||
bForOk = hb_cdxEvalCond ( pArea, pForItem, FALSE );
|
||
}
|
||
|
||
if ( bForOk )
|
||
{
|
||
double d;
|
||
|
||
if ( pTag->nField )
|
||
{
|
||
SELF_GETVALUE( ( AREAP ) pArea, pTag->nField, pItem );
|
||
}
|
||
else if ( hb_itemType( pTag->pKeyItem ) == HB_IT_BLOCK )
|
||
{
|
||
hb_vmPushSymbol( &hb_symEval );
|
||
hb_vmPush( pTag->pKeyItem );
|
||
hb_vmSend( 0 );
|
||
hb_itemCopy( pItem, &(HB_VM_STACK.Return) );
|
||
}
|
||
else
|
||
{
|
||
pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pKeyItem );
|
||
hb_macroRun( pMacro );
|
||
hb_itemCopy( pItem, hb_stackItemFromTop( -1 ) );
|
||
hb_stackPop();
|
||
}
|
||
|
||
switch( hb_itemType( pItem ) )
|
||
{
|
||
case HB_IT_STRING:
|
||
hb_cdxSortInsertWord( pSort, ( LONG ) pArea->ulRecNo,
|
||
pItem->item.asString.value,
|
||
HB_CDXMAXKEY( pItem->item.asString.length ) );
|
||
break;
|
||
|
||
case HB_IT_INTEGER:
|
||
case HB_IT_LONG:
|
||
#ifndef HB_LONG_LONG_OFF
|
||
case HB_IT_LONGLONG:
|
||
#endif
|
||
case HB_IT_DOUBLE:
|
||
d = hb_itemGetND( pItem );
|
||
HB_DBL2ORD( &d, &cTemp[0] );
|
||
hb_cdxSortInsertWord( pSort, pArea->ulRecNo, (char *) cTemp, 8 );
|
||
break;
|
||
|
||
case HB_IT_DATE:
|
||
d = (double) pItem->item.asDate.value;
|
||
HB_DBL2ORD( &d, &cTemp[0] );
|
||
hb_cdxSortInsertWord( pSort, pArea->ulRecNo, (char *) cTemp, 8 );
|
||
break;
|
||
|
||
case HB_IT_LOGICAL:
|
||
cTemp[0] = (BYTE) (hb_itemGetL( pItem ) ? 'T' : 'F');
|
||
hb_cdxSortInsertWord( pSort, pArea->ulRecNo, (char *) cTemp, 1 );
|
||
break;
|
||
|
||
default:
|
||
printf( "hb_cdxTagDoIndex: hb_itemType( pItem ) = %i", hb_itemType( pItem ) );
|
||
}
|
||
}
|
||
if ( pEvalItem )
|
||
{
|
||
if ( pArea->lpdbOrdCondInfo->lStep )
|
||
{
|
||
lStep ++;
|
||
if ( lStep == pArea->lpdbOrdCondInfo->lStep )
|
||
lStep = 0;
|
||
}
|
||
if ( lStep == 0 )
|
||
{
|
||
if ( !hb_cdxEvalCond ( pArea, pEvalItem, FALSE ) )
|
||
break;
|
||
}
|
||
}
|
||
if ( !bDirectRead )
|
||
{
|
||
if ( bEnd )
|
||
break;
|
||
if ( pArea->lpdbOrdCondInfo && pArea->lpdbOrdCondInfo->lNextCount > 0 )
|
||
{
|
||
pArea->lpdbOrdCondInfo->lNextCount--;
|
||
if ( pArea->lpdbOrdCondInfo->lNextCount <= 0 )
|
||
break;
|
||
}
|
||
SELF_SKIP( ( AREAP ) pArea, 1 );
|
||
if ( pArea->fEof )
|
||
break;
|
||
}
|
||
}
|
||
if ( pSort->WordCount + pSort->TotalWordCount > 0 )
|
||
hb_cdxSortDisplayWord( pSort );
|
||
else
|
||
hb_cdxTagEmptyIndex( pTag );
|
||
hb_cdxSortFree( pSort );
|
||
hb_itemRelease( pItem );
|
||
|
||
hb_set.HB_SET_DELETED = bSaveDeleted;
|
||
pArea->dbfi.itmCobExpr = pSaveFilter;
|
||
pArea->uiTag = uiSaveTag;
|
||
pTag->TagChanged = TRUE;
|
||
}
|
||
pTag->pIndex->pArea->ulRecNo = 0;
|
||
#ifndef HB_CDP_SUPPORT_OFF
|
||
s_cdpage = cdpTmp;
|
||
#endif
|
||
}
|
||
|