diff --git a/harbour/ChangeLog b/harbour/ChangeLog index a56d68707b..9680be962e 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -8,6 +8,70 @@ 2002-12-01 13:30 UTC+0100 Foo Bar */ +2007-05-04 10:15 UTC+0100 Miguel Angel Marchuet (miguelangel/at/marchuet.net) + + contrib/bmdbfcdx/Makefile + + contrib/bmdbfcdx/bmdbfcdx1.c + + contrib/bmdbfcdx/bmsixcdx1.c + + contrib/bmdbfcdx/hbrddbmcdx.h + + contrib/bmdbfcdx/make_b32.bat + + contrib/bmdbfcdx/makefile.bc + + contrib/bmdbfcdx/readme.txt + + BMDBFCDX RDD: + + Is a DBFCDX RDD compatible with clipper 5.3, use SET OPTIMIZE ON to make a + static bitmap filters, with SET OPTIMIZE OFF works as harbour DBFCDX. + + Addons: + + BM_DbSeekWild( uKey, [lSoftSeek], [lFindLast], [lNext], [lAll] ) => .T./.F. or aSeekRec when lAll clause + BM_Turbo( lOnOff ) // Is only recomendable to use it on creating FILTERS + BM_DbGetFilterArray() => aFilterRec + BM_DbSetFilterArray( aFilterRec ) + BM_DbSetFilterArrayAdd( aFilterRec ) + BM_DbSetFilterArrayDel( aFilterRec ) + + Respecting command: + + SET OPTIMIZE + Change the setting that determines whether to optimize using the open orders + when processing a filtered database file + ------------------------------------------------------------------------------ + Syntax + + SET OPTIMIZE ON | OFF | () + + Arguments + + ON enables optimization. + + OFF disables optimization. + + is a logical expression that must be enclosed in + parentheses. A value of true (.T.) is the same as ON, and a value of + false (.F.) is the same as OFF. + + Note: The initial default of this setting depends on the RDD. + + Description + + For RDDs that support optimization, such as BMDBFCDX, SET OPTIMIZE + determines whether to optimize filters based on the orders open in the + current work area. If this flag is ON, the RDD will optimize the search + for records that meet the filter condition to the fullest extent + possible, minimizing the need to read the actual data from the database + file. + + If this flag is OFF, the RDD will not optimize. + + Examples + + ¦ The following example enables optimization for the Inventor + database file using the SET OPTIMIZE command: + + USE Inventor NEW VIA "BMDBFCDX" + SET OPTIMIZE ON + + 2007-05-03 16:22 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) * harbour/source/rdd/usrrdd/usrrdd.c * updated casting for recent modifications in RDD API diff --git a/harbour/contrib/Makefile b/harbour/contrib/Makefile index 71f5bdf6c6..ccf9e03751 100644 --- a/harbour/contrib/Makefile +++ b/harbour/contrib/Makefile @@ -12,6 +12,7 @@ DIRS=\ libmisc \ libnf \ samples \ + bmdbfcdx \ ifeq ($(HB_ARCHITECTURE),w32) diff --git a/harbour/contrib/bmdbfcdx/Makefile b/harbour/contrib/bmdbfcdx/Makefile new file mode 100644 index 0000000000..e4a6aefb15 --- /dev/null +++ b/harbour/contrib/bmdbfcdx/Makefile @@ -0,0 +1,13 @@ +# +# $Id$ +# + +ROOT = ../../../ + +C_SOURCES=\ + bmdbfcdx1.c \ + bmsixcdx1.c + +LIBNAME=bmdbfcdx + +include $(TOP)$(ROOT)config/lib.cf diff --git a/harbour/contrib/bmdbfcdx/bmdbfcdx1.c b/harbour/contrib/bmdbfcdx/bmdbfcdx1.c new file mode 100644 index 0000000000..eb4a15546f --- /dev/null +++ b/harbour/contrib/bmdbfcdx/bmdbfcdx1.c @@ -0,0 +1,10229 @@ +/* + * $Id$ + */ + +/* + * xHarbour Project source code: + * BMDBFCDX RDD (ver.2) + * + * Copyright 1999-2002 Bruno Cantero + * Copyright 2000-2003 Horacio Roldan (portions) + * Copyright 2003 Przemyslaw Czerpak - all code except + * hb_cdxTagDoIndex and related hb_cdxSort* rewritten. + * Copyright 2004 Przemyslaw Czerpak - rest of code rewritten + * Copyright 2006 Miguel Angel Marchuet + * BM_DbSeekWild( uKey, [lSoftSeek], [lFindLast], [lNext], [lAll] ) => .T./.F. or aSeekRec when lAll clause + * BM_Turbo( lOnOff ) + * BM_DbGetFilterArray() => aFilterRec + * BM_DbSetFilterArray( aFilterRec ) + * BM_DbSetFilterArrayAdd( aFilterRec ) + * BM_DbSetFilterArrayDel( aFilterRec ) + * hb_cdxAppend + * hb_cdxCheckRecordFilter + * hb_cdxClearFilter + * hb_cdxDeleteRec + * hb_cdxPutRec + * hb_cdxRecall + * hb_cdxSetFilter + * hb_cdxSkipFilter + * IMPLEMENTATION of Bitmap filters + * 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_CLIP_AUTOPEN +#define HB_CDX_NEW_SORT + +#if !defined( HB_SIXCDX ) +# define HB_CDX_PACKTRAIL +#endif + +#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 "hbapiitm.h" +#include "hbinit.h" +#include "hbapierr.h" +#include "hbapilng.h" +#include "hbvm.h" +#include "hbset.h" +#include "hbrddbmcdx.h" +#include "hbmath.h" +#include "rddsys.ch" +#include "hbregex.h" + +#ifndef HB_CDP_SUPPORT_OFF + /* for nation sorting support */ + #include "hbapicdp.h" + #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 + +/* + * 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, BOOL fReindex ); + +/* 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 ); + +/* free create index structur */ +static void hb_cdxSortFree( LPCDXSORTINFO pSort ); + +static BOOL hb_cdxPageReadTopKey( LPCDXPAGE pPage ); + +static BOOL hb_cdxPageReadNextKey( LPCDXPAGE pPage ); + +static LPCDXTAG hb_cdxGetActiveTag( CDXAREAP pArea ); + +static void hb_cdxClearLogPosInfo( CDXAREAP pArea ); + +static USHORT s_uiRddId = ( USHORT ) -1; + +static BOOL bTurbo = FALSE; +static RDDFUNCS cdxSuper; +static const 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_ULP ) hb_cdxRecNo, + ( DBENTRYP_I ) hb_cdxRecId, + ( 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_OI ) 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, + ( DBENTRYP_B ) hb_cdxLocate, + + + /* Miscellaneous */ + + ( DBENTRYP_P ) hb_cdxCompile, + ( DBENTRYP_I ) hb_cdxError, + ( DBENTRYP_I ) hb_cdxEvalBlock, + + + /* Network operations */ + + ( DBENTRYP_VSP ) hb_cdxRawLock, + ( DBENTRYP_VL ) hb_cdxLock, + ( DBENTRYP_I ) hb_cdxUnLock, + + + /* Memofile functions */ + + ( DBENTRYP_V ) hb_cdxCloseMemFile, + ( DBENTRYP_VP ) hb_cdxCreateMemFile, + ( DBENTRYP_SVPB ) hb_cdxGetValueFile, + ( DBENTRYP_VP ) hb_cdxOpenMemFile, + ( DBENTRYP_SVPB ) hb_cdxPutValueFile, + + + /* Database file header handling */ + + ( DBENTRYP_V ) hb_cdxReadDBHeader, + ( DBENTRYP_V ) hb_cdxWriteDBHeader, + + + /* non WorkArea functions */ + ( DBENTRYP_R ) hb_cdxInit, + ( DBENTRYP_R ) hb_cdxExit, + ( DBENTRYP_RVV ) hb_cdxDrop, + ( DBENTRYP_RVV ) hb_cdxExists, + ( DBENTRYP_RSLV ) hb_cdxRddInfo, + + + /* Special and reserved methods */ + + ( DBENTRYP_SVP ) hb_cdxWhoCares +}; + + +#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 +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 cdxTimeIdxBld = 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 BMDBFCDX function + */ + + +/* + * generate internal error + */ +static void hb_cdxErrInternal( char * szMsg ) +{ + hb_errInternal( 9201, szMsg ? szMsg : "hb_cdxErrInternal: data integrity error.", "", "" ); +} + +/* + * generate Run-Time error + */ +static ERRCODE hb_cdxErrorRT( CDXAREAP pArea, USHORT uiGenCode, USHORT uiSubCode, char * filename, USHORT uiOsCode, USHORT uiFlags ) +{ + PHB_ITEM pError; + ERRCODE iRet = FAILURE; + + if ( hb_vmRequestQuery() == 0 ) + { + pError = hb_errNew(); + hb_errPutGenCode( pError, uiGenCode ); + hb_errPutSubCode( pError, uiSubCode ); + hb_errPutOsCode( pError, uiOsCode ); + 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_errRelease( 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; +} + +/* + * get CDX key type for given item + */ +static BYTE hb_cdxItemType( PHB_ITEM pItem ) +{ + switch( hb_itemType( pItem ) ) + { + case HB_IT_STRING: + case HB_IT_STRING | HB_IT_MEMO: + return 'C'; + + case HB_IT_INTEGER: + case HB_IT_LONG: + case HB_IT_DOUBLE: + return 'N'; + + case HB_IT_DATE: + return 'D'; + + case HB_IT_LOGICAL: + return 'L'; + + default: + return 'U'; + } +} + + +/* + * store Item in index key + * TODO: uiType check and generate RT error if necessary + */ +static LPCDXKEY hb_cdxKeyPutItem( LPCDXKEY pKey, PHB_ITEM pItem, ULONG ulRec, LPCDXTAG pTag, BOOL fTrans, BOOL fSize ) +{ + BYTE buf[CDX_MAXKEY], *ptr; + ULONG ulLen = 0; + double d; + + ptr = &buf[0]; + + switch ( hb_cdxItemType( pItem ) ) + { + case 'C': + ulLen = hb_itemGetCLen( pItem ); + if( ulLen > (ULONG) pTag->uiLen ) + ulLen = pTag->uiLen; + if ( fSize && ulLen < (ULONG) pTag->uiLen ) + { + memcpy( ptr, hb_itemGetCPtr( pItem ), ulLen ); + memset( ptr + ulLen, pTag->bTrail, pTag->uiLen - ulLen ); + ulLen = pTag->uiLen; + } + else + { + ptr = ( BYTE * ) hb_itemGetCPtr( pItem ); + } + break; + case 'N': + d = hb_itemGetND( pItem ); + HB_DBL2ORD( &d, ptr ); + ulLen = 8; + break; + case 'D': + d = (double) hb_itemGetDL( pItem ); + HB_DBL2ORD( &d, ptr ); + ulLen = 8; + break; + case 'L': + *ptr = (BYTE) ( hb_itemGetL( pItem ) ? 'T' : 'F' ); + ulLen = 1; + break; + default: + ptr = NULL; + break; + } + pKey = hb_cdxKeyPut( pKey, ptr, ( USHORT ) ulLen, ulRec ); +#ifndef HB_CDP_SUPPORT_OFF + if ( fTrans && pTag->uiType == 'C' ) + hb_cdpnTranslate( ( char * ) pKey->val, hb_cdp_page, pTag->pIndex->pArea->cdPage, pKey->len ); +#endif + return pKey; +} + +/* + * get Item from index key + */ +static PHB_ITEM hb_cdxKeyGetItem( LPCDXKEY pKey, PHB_ITEM pItem, LPCDXTAG pTag, BOOL fTrans ) +{ + double d; + + if ( pKey ) + { + switch( pTag->uiType ) + { + case 'C': +#ifndef HB_CDP_SUPPORT_OFF + if( fTrans && pTag->pIndex->pArea->cdPage != hb_cdp_page ) + { + char * pVal = ( char * ) hb_xgrab( pKey->len + 1 ); + memcpy( pVal, pKey->val, pKey->len ); + pVal[ pKey->len ] = '\0'; + hb_cdpnTranslate( pVal, pTag->pIndex->pArea->cdPage, hb_cdp_page, + pKey->len ); + pItem = hb_itemPutCPtr( pItem, pVal, pKey->len ); + } + else +#endif + { + 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: + if ( pItem ) + hb_itemClear( pItem ); + else + pItem = hb_itemNew( NULL ); + } + } + else if ( pItem ) + hb_itemClear( pItem ); + else + pItem = hb_itemNew( NULL ); + + return pItem; +} + +/* + * evaluate key expression and create new Key from the result + */ +static LPCDXKEY hb_cdxKeyEval( LPCDXKEY pKey, LPCDXTAG pTag ) +{ + CDXAREAP pArea = pTag->pIndex->pArea; + PHB_ITEM pItem; +#ifndef HB_CDP_SUPPORT_OFF + /* TODO: this hack is not thread safe, hb_cdp_page has to be thread specific */ + PHB_CODEPAGE cdpTmp = hb_cdp_page; + hb_cdp_page = pArea->cdPage; +#endif + + if ( pTag->nField ) + { + 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 + { + int iCurrArea = hb_rddGetCurrentWorkAreaNumber(); + + if ( iCurrArea != pArea->uiArea ) + hb_rddSelectWorkAreaNumber( pArea->uiArea ); + else + iCurrArea = 0; + + pItem = hb_vmEvalBlockOrMacro( pTag->pKeyItem ); + pKey = hb_cdxKeyPutItem( pKey, pItem, pArea->ulRecNo, pTag, FALSE, TRUE ); + + if ( iCurrArea ) + hb_rddSelectWorkAreaNumber( iCurrArea ); + } + +#ifndef HB_CDP_SUPPORT_OFF + hb_cdp_page = cdpTmp; +#endif + + return pKey; +} + +/* + * evaluate conditional expression and return the result + */ +static BOOL hb_cdxEvalCond( CDXAREAP pArea, PHB_ITEM pCondItem, BOOL fSetWA ) +{ + int iCurrArea = 0; + BOOL fRet; + + if ( fSetWA ) { + iCurrArea = hb_rddGetCurrentWorkAreaNumber(); + if ( iCurrArea != pArea->uiArea ) + hb_rddSelectWorkAreaNumber( pArea->uiArea ); + else + iCurrArea = 0; + } + + fRet = hb_itemGetL( hb_vmEvalBlockOrMacro( pCondItem ) ); + + if ( iCurrArea ) + hb_rddSelectWorkAreaNumber( iCurrArea ); + + return fRet; +} + +/* + * evaluate seek/skip block: {|key, rec| ... } + */ +static BOOL hb_cdxEvalSeekCond( LPCDXTAG pTag, PHB_ITEM pCondItem ) +{ + BOOL fRet; + PHB_ITEM pKeyVal, pKeyRec; + + pKeyVal = hb_cdxKeyGetItem( pTag->CurKey, NULL, pTag, TRUE ); + pKeyRec = hb_itemPutNInt( NULL, pTag->CurKey->rec ); + + fRet = hb_itemGetL( hb_vmEvalBlockV( pCondItem, 2, pKeyVal, pKeyRec ) ); + + hb_itemRelease( pKeyVal ); + hb_itemRelease( pKeyRec ); + + return fRet; +} + +/* + * check if Key is in top scope + */ +static BOOL hb_cdxTopScope( LPCDXTAG pTag ) +{ + LPCDXKEY pKey; + + if ( pTag->UsrAscend ) + { + pKey = pTag->topScopeKey; + return !pKey || !pKey->len || + hb_cdxValCompare( pTag, pKey->val, pKey->len, + pTag->CurKey->val, pTag->CurKey->len, FALSE ) <= 0; + } + else + { + pKey = pTag->bottomScopeKey; + return !pKey || !pKey->len || + hb_cdxValCompare( pTag, pKey->val, pKey->len, + pTag->CurKey->val, pTag->CurKey->len, FALSE ) >= 0; + } +} + +/* + * check if Key is in bottom scope + */ +static BOOL hb_cdxBottomScope( LPCDXTAG pTag ) +{ + LPCDXKEY pKey; + + if ( pTag->UsrAscend ) + { + pKey = pTag->bottomScopeKey; + return !pKey || !pKey->len || + hb_cdxValCompare( pTag, pKey->val, pKey->len, + pTag->CurKey->val, pTag->CurKey->len, FALSE ) >= 0; + } + else + { + pKey = pTag->topScopeKey; + return !pKey || !pKey->len || + hb_cdxValCompare( pTag, pKey->val, pKey->len, + pTag->CurKey->val, pTag->CurKey->len, FALSE ) <= 0; + } +} + +/* + * clear top or bottom scope + */ +static void hb_cdxTagClearScope( LPCDXTAG pTag, USHORT nScope ) +{ + CDXAREAP pArea = pTag->pIndex->pArea; + LPCDXKEY *pScopeKey; + PHB_ITEM *pScope; + + HB_TRACE(HB_TR_DEBUG, ("hb_cdxTagClearScope(%p, %hu)", pTag, nScope)); + + /* resolve any pending scope relations first */ + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + if ( pTag->UsrAscend ? nScope == 0 : 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; + pTag->curKeyState &= ~( CDX_CURKEY_RAWCNT | CDX_CURKEY_LOGCNT ); + if ( nScope == 0 ) + pTag->curKeyState &= ~( CDX_CURKEY_RAWPOS | CDX_CURKEY_LOGPOS ); + } +} + +/* + * set top or bottom scope + */ +static void hb_cdxTagSetScope( LPCDXTAG pTag, USHORT nScope, PHB_ITEM pItem ) +{ + CDXAREAP pArea = pTag->pIndex->pArea; + PHB_ITEM pScopeVal; + + /* resolve any pending scope relations first */ + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + pScopeVal = ( hb_itemType( pItem ) == HB_IT_BLOCK ) ? + hb_vmEvalBlock( pItem ) : pItem; + + if ( pTag->uiType == hb_cdxItemType( pScopeVal ) ) + { + PHB_ITEM *pScope; + LPCDXKEY *pScopeKey; + ULONG ulRec; + + if ( pTag->UsrAscend ? nScope == 0 : nScope != 0 ) + { + pScope = &(pTag->topScope); + pScopeKey = &(pTag->topScopeKey); + ulRec = CDX_IGNORE_REC_NUM; + } + else + { + pScope = &(pTag->bottomScope); + pScopeKey = &(pTag->bottomScopeKey); + ulRec = CDX_MAX_REC_NUM; + } + + if ( *pScope == NULL ) + *pScope = hb_itemNew( NULL ); + hb_itemCopy( *pScope, pItem ); + *pScopeKey = hb_cdxKeyPutItem( *pScopeKey, pScopeVal, ulRec, pTag, TRUE, FALSE ); + pTag->curKeyState &= ~( CDX_CURKEY_RAWCNT | CDX_CURKEY_LOGCNT ); + if ( nScope == 0 ) + pTag->curKeyState &= ~( CDX_CURKEY_RAWPOS | CDX_CURKEY_LOGPOS ); + } + else + { + /* TODO: !!! + * RT error: BMDBFCDX/1051 Scope Type Mismatch + * hb_cdxErrorRT + */ + } +} + +static void hb_cdxTagGetScope( LPCDXTAG pTag, USHORT nScope, PHB_ITEM pItem ) +{ + CDXAREAP pArea = pTag->pIndex->pArea; + PHB_ITEM *pScope; + + /* resolve any pending scoped relations first */ + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + pScope = ( pTag->UsrAscend ? nScope == 0 : nScope != 0 ) ? + &(pTag->topScope) : &(pTag->bottomScope); + if ( *pScope ) + hb_itemCopy( pItem, *pScope ); + else + hb_itemClear( pItem ); +} + +/* + * refresh top and bottom scope value if set as codeblock + */ +static void hb_cdxTagRefreshScope( LPCDXTAG pTag ) +{ + PHB_ITEM pItem; + + if( pTag->pIndex->pArea->lpdbPendingRel && + pTag->pIndex->pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pTag->pIndex->pArea ); + + if ( hb_itemType( pTag->topScope ) == HB_IT_BLOCK ) + { + pItem = hb_vmEvalBlock( pTag->topScope ); + pTag->topScopeKey = hb_cdxKeyPutItem( pTag->topScopeKey, pItem, + pTag->topScopeKey->rec, pTag, TRUE, FALSE ); + } + if ( hb_itemType( pTag->bottomScope ) == HB_IT_BLOCK ) + { + pItem = hb_vmEvalBlock( pTag->bottomScope ); + pTag->bottomScopeKey = hb_cdxKeyPutItem( pTag->bottomScopeKey, pItem, + pTag->bottomScopeKey->rec, pTag, TRUE, FALSE ); + } +} + +#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_fsSeekLarge( hFile, ulPos, FS_SET ) != ( HB_FOFFSET ) ulPos || + hb_fsRead( hFile, (BYTE *) byBuf, 4 ) != 4 ) + hb_errInternal( EDBF_READ, "hb_cdxIndexGetAvailPage: Read index page failed.", "", "" ); + pIndex->freePage = HB_GET_LE_UINT32( byBuf ); +#ifdef HB_CDX_DBGUPDT + cdxReadNO++; +#endif + } + } + else + { + int iCnt = ( bHeader ? CDX_HEADERPAGES : 1 ); + + if ( pIndex->nextAvail != CDX_DUMMYNODE ) + ulPos = pIndex->nextAvail; + else + ulPos = ( ULONG ) hb_fsSeekLarge( hFile, 0, FS_END ); + pIndex->nextAvail = ulPos + iCnt * CDX_PAGELEN; + + /* TODO: ### */ + if ( bHeader ) + { + BYTE byBuf[CDX_PAGELEN]; + memset( byBuf, 0, CDX_PAGELEN ); + if ( hb_fsSeekLarge( hFile, ulPos, FS_SET ) != ( HB_FOFFSET ) 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)", "", "" ); + } + pIndex->fChanged = TRUE; + } + } + return ulPos; +} + +/* + * free index page + */ +static void hb_cdxIndexPutAvailPage( LPCDXINDEX pIndex, ULONG ulPos, BOOL bHeader ) +{ + if ( ulPos != 0 && ulPos != CDX_DUMMYNODE ) + { + int iCnt = ( bHeader ? CDX_HEADERPAGES : 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; + BOOL fClean = TRUE; + + 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.", "", "" ); + + ulPos = pIndex->freePage; + while ( pLst && pLst->fStat ) + { + if ( fClean ) + { + memset( byPageBuf, 0, CDX_PAGELEN ); + fClean = FALSE; + } + HB_PUT_LE_UINT32( byPageBuf, pLst->ulAddr ); + if ( hb_fsSeekLarge( pIndex->hFile, ulPos, FS_SET ) != ( HB_FOFFSET ) 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_fsSeekLarge( pIndex->hFile, ulPos, FS_SET ) != ( HB_FOFFSET ) 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_fsSeekLarge( pIndex->hFile, ulPos, FS_SET ) != ( HB_FOFFSET ) ulPos || + hb_fsRead( pIndex->hFile, pBuffer, uiSize ) != uiSize ) + hb_errInternal( EDBF_READ, "hb_cdxIndexPageRead: 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_UINT32( &byBuf[0] ); + ulVer = HB_GET_BE_UINT32( &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 it's for test only */ + /* 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->pArea->fShared || !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 + + if ( bTurbo ) + { + pIndex->lockRead++; + hb_cdxIndexCheckVersion( pIndex ); + return TRUE; + } + else + { + ret = hb_dbfLockIdxFile( pIndex->hFile, pIndex->pArea->bLockType, + FL_LOCK | FLX_SHARED | FLX_WAIT, &pIndex->ulLockPos ); + if ( !ret ) + hb_cdxErrorRT( pIndex->pArea, EG_LOCK, EDBF_LOCK, pIndex->szFileName, hb_fsError(), 0 ); + + 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->fReadonly ) + hb_errInternal( 9101, "hb_cdxIndexLockWrite: readonly index.", "", "" ); + if ( pIndex->lockRead ) + hb_errInternal( 9105, "hb_cdxIndexLockWrite: 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->pArea->fShared || !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 ) + hb_cdxErrorRT( pIndex->pArea, EG_LOCK, EDBF_LOCK, pIndex->szFileName, hb_fsError(), 0 ); + + 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 ( bTurbo ) + { +#ifdef HB_CDX_DBGCODE + if ( pIndex->pArea->fShared && pIndex->fShared ) + pIndex->RdLck = FALSE; +#endif + } + else + { + if ( pIndex->pArea->fShared && 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_cdxIndexUnLockWrite: 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->pArea->fShared && pIndex->fShared ) + { + if ( pIndex->fChanged ) + { + BYTE byBuf[8]; + (pIndex->ulVersion)++; + HB_PUT_LE_UINT32( &byBuf[0], pIndex->freePage ); + HB_PUT_BE_UINT32( &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->fFlush = TRUE; + 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_UINT32( &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; + pIndex->fFlush = TRUE; +#ifdef HB_CDX_DBGUPDT + cdxWriteNO++; +#endif + } + else if ( pIndex->fChanged ) + { + pIndex->fFlush = TRUE; + } + 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; + pIndex->pCompound->curKeyState = 0; + if ( pIndex->pCompound->CurKey ) + pIndex->pCompound->CurKey->rec = 0; + } + pTag = pIndex->TagList; + while ( pTag ) + { + hb_cdxTagClose( pTag ); + hb_cdxTagPoolFree( pTag, 0 ); + pTag->fRePos = TRUE; + pTag->curKeyState = 0; + 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 = pPage->TagParent->bTrail; + 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_UINT16( &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_UINT32( &pPage->pKeyBuf[ ( iKey + 1 ) * ( pPage->TagParent->uiLen + 6 ) - 6 ] ); + else if ( pPage->PageType & CDX_NODE_LEAF ) + return HB_GET_LE_UINT32( &pPage->node.extNode.keyPool[ iKey * pPage->ReqByte ] ) & pPage->RNMask; + else + return HB_GET_BE_UINT32( &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_UINT32( &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, BOOL fSpc ) +{ + SHORT iNum = pPage->TagParent->uiLen, iKey, iPos, iFree = CDX_EXT_FREESPACE; + SHORT iLen = iNum + 6; + BYTE bDup, bTrl; + BYTE bTrail = pPage->TagParent->bTrail; + 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 ) + { +#ifdef HB_CDX_PACKTRAIL + SHORT iMax = iNum - bTrl; +#else + SHORT iMax = iNum - HB_MAX( pKeyBuf[ iPos - 1 ], bTrl ); +#endif + 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 (bTrl=%d), iKey=%d/%d\r\n", bDup, pKeyBuf[ iPos + iNum + 4 ], bTrl, 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_UINT32( &pKeyBuf[ iPos + iNum - iLen ] ) >= + HB_GET_LE_UINT32( &pKeyBuf[ iPos + iNum ] ) ) ) + { + printf( "\r\nikey=%d, iKeys=%d, K=%d, ulRecPrev=%ld, ulRec=%ld", + iKey, iKeys, K, + (ULONG) HB_GET_LE_UINT32( &pKeyBuf[ iPos + iNum - iLen ] ), + (ULONG) HB_GET_LE_UINT32( &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; + } + } + iFree -= iNum + pPage->ReqByte - bDup - bTrl; + } + if ( fSpc && ( iFree != pPage->iFree /* || iFree < 0 */ ) ) + { + printf( "\r\nFreeSpace calculated wrong! iFree=%d, pPage->iFree=%d", + iFree, pPage->iFree ); + fflush(stdout); + bErr = TRUE; + } + if ( bErr ) + { + printf("\r\nPage=%lx, Page->iFree=%d, iLen=%d\r\n", pPage->Page, pPage->iFree, iNum ); + fflush(stdout); + hb_cdxErrInternal( "hb_cdxPageCheckDupTrl: index corrupted." ); + } +} + +static void hb_cdxPageLeafDecode( LPCDXPAGE pPage, BYTE * pKeyBuf ); +static void hb_cdxPageCheckDupTrlRaw( LPCDXPAGE pPage ) +{ + BYTE *pKeyBuf = (BYTE *) hb_xgrab( pPage->iKeys * ( pPage->TagParent->uiLen + 6 ) ); + + hb_cdxPageLeafDecode( pPage, pKeyBuf ); + hb_cdxPageCheckDupTrl( pPage, pKeyBuf, pPage->iKeys, TRUE ); + hb_xfree( pKeyBuf ); +} +#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 ] = ( BYTE ) ( ulRec & 0xff ); + else if ( i == iReq - 2 ) + pDst[ i ] = ( BYTE ) ( ulRec & 0xff ) | ( usBit & 0xff ); + else + pDst[ i ] = ( BYTE ) ( 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, TRUE ); +#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_UINT32( &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, (int) (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, TRUE ); +#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->bTrail; + 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_UINT16( 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_UINT32( pRec ) & pPage->RNMask; + HB_PUT_LE_UINT32( 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 number 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, FALSE ); +#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_UINT32( 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, iFree=%d", + pPage->Page, iKey, pPage->iKeys, + (ULONG) HB_GET_LE_UINT32( &pPage->pKeyBuf[ ( iKey + 1 ) * iLen - 6 ] ), + pPage->iFree ); + 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; +#ifdef HB_CDX_PACKTRAIL + iNum -= pPage->pKeyBuf[ iNext + iLen - 1 ]; +#else + iNum -= HB_MAX( pPage->pKeyBuf[ iNext + iLen - 1 ], + pPage->pKeyBuf[ iPrev + iLen - 1 ] ); +#endif + 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; + } +#ifdef HB_CDX_DSPDBG_INFO + printf("+%d=%d", iSpc+iDup, pPage->iFree+iSpc+iDup ); + if ( iSpc+iDup < 0 ) + printf( " iLen=%d, iDup=%d, iNum=%d pd=%d pt=%d cd=%d ct=%d nd=%d nt=%d", + iLen-6, iDup, iNum, + pPage->pKeyBuf[ iPrev + iLen - 2 ], + pPage->pKeyBuf[ iPrev + iLen - 1 ], + pPage->pKeyBuf[ ( iKey + 1 ) * iLen - 2 ], + pPage->pKeyBuf[ ( iKey + 1 ) * iLen - 1 ], + pPage->pKeyBuf[ iNext + iLen - 2 ], + pPage->pKeyBuf[ iNext + iLen - 1 ] ); + fflush(stdout); +#endif + } + 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, TRUE ); +#endif + if ( iKey >= pPage->iKeys ) + iRet |= NODE_NEWLASTKEY; + if ( pPage->iKeys == 0 ) + iRet |= NODE_JOIN; + else if ( pPage->iFree < 0 ) + iRet |= NODE_SPLIT; + /* 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->bTrail; + 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, TRUE ); +#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_UINT32( &pPage->pKeyBuf[ iPos + iNum ], pKey->rec ); + while ( iTrl < iNum && pPage->pKeyBuf[ iPos + iNum - iTrl - 1 ] == bTrail ) + ++iTrl; + if ( iKey > 0 ) + { +#ifdef HB_CDX_PACKTRAIL + iMax = iNum - iTrl; +#else + iMax = iNum - HB_MAX( iTrl, pPage->pKeyBuf[ iPos - 1 ] ); +#endif + 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 ) + { +#ifdef HB_CDX_PACKTRAIL + iMax = iNum - pPage->pKeyBuf[ iPos + iLen + iLen - 1 ]; +#else + iMax = iNum - HB_MAX( iTrl, pPage->pKeyBuf[ iPos + iLen + iLen - 1 ] ); +#endif + 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, TRUE ); +#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->bTrail, iLen ); + if ( ulRec ) + HB_PUT_BE_UINT32( &pPage->node.intNode.keyPool[ iPos + iLen ], ulRec ); + HB_PUT_BE_UINT32( &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, + (ULONG) HB_GET_BE_UINT32( &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_UINT16( pPage->node.intNode.attr ); + pPage->Left = HB_GET_LE_UINT32( pPage->node.intNode.leftPtr ); + pPage->Right = HB_GET_LE_UINT32( pPage->node.intNode.rightPtr ); + pPage->iKeys = HB_GET_LE_UINT16( pPage->node.intNode.nKeys ); + pPage->fChanged = FALSE; + + if ( ( pPage->PageType & CDX_NODE_LEAF ) != 0 ) + { + pPage->iFree = HB_GET_LE_UINT16( pPage->node.extNode.freeSpc ); + pPage->RNMask = HB_GET_LE_UINT32( 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_UINT16( pPage->node.intNode.attr, pPage->PageType ); + HB_PUT_LE_UINT16( pPage->node.intNode.nKeys, pPage->iKeys ); + HB_PUT_LE_UINT32( pPage->node.intNode.leftPtr, pPage->Left ); + HB_PUT_LE_UINT32( pPage->node.intNode.rightPtr, pPage->Right ); + + if ( ( pPage->PageType & CDX_NODE_LEAF ) != 0 ) + { + HB_PUT_LE_UINT16( pPage->node.extNode.freeSpc, pPage->iFree ); + HB_PUT_LE_UINT32( 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; + } +#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; +#ifdef HB_CDX_PACKTRAIL + bMax = iLen - 6 - pPtr[ iLen - 1 ]; +#else + bMax = iLen - 6 - HB_MAX( pPtr[ iLen - 1 ], pPtr[ -1 ] ); +#endif + 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, FALSE ); +#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 1 + if ( !fIns && lpTmpPage != NULL ) + { + SHORT j, iSize = 0, iMaxReq; + ULONG ulMaxRec = 0, ul; + BYTE * pbKey, bMax; + + for ( j = 0; j < iKeys; j++ ) + { + if ( ulMaxRec < ( ul = HB_GET_LE_UINT32( &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 = ( HB_GET_LE_UINT16( &lpTmpPage->node.extNode.keyPool[ lpTmpPage->ReqByte - 2 ] ) + >> ( 16 - lpTmpPage->TCBits ) ) & lpTmpPage->TCMask; +#ifdef HB_CDX_PACKTRAIL + bMax = iLen - 6 - bMax; +#else + bMax = iLen - 6 - HB_MAX( pPtr[ iKeys * iLen - 1 ], bMax ); +#endif + for ( j = 0; j < bMax && + pPtr[ ( iKeys - 1 ) * iLen + j ] == pbKey[ j ]; j++ ) {} +#ifdef HB_CDX_DSPDBG_INFO + printf("\r\nbDup=%d, bTrl=%d ", j, iLen - 6 - bMax ); fflush(stdout); +#endif + 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 + { +#ifdef HB_CDX_DSPDBG_INFO + printf("\r\ninserting bDup=%d #keys=%d/%d (%d) parent=%lx, child=%lx (%d), rec=%ld", + j, iKeys, lpTmpPage->iKeys, i, pPage->Page, lpTmpPage->Page, iSize, (ULONG) HB_GET_LE_UINT32( 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 ); +#ifdef HB_CDX_PACKTRAIL + bMax = iLen - 6 - pPtr[ iLen - 1 ]; +#else + bMax = iLen - 6 - HB_MAX( pPtr[ iLen - 1 ], pPtr[ -1 ] ); +#endif + while ( bDup < bMax && pPtr[ bDup ] == pPtr[ bDup - iLen ] ) + ++bDup; + pPtr[ iLen - 2 ] = bDup; + iKeys += lpTmpPage->iKeys; +#ifdef HB_CDX_DSPDBG_INFO + printf(" bDup2=%d, bTrl2=%d ", bDup, pPtr[ iLen - 1 ] ); fflush(stdout); +#endif + } + pPtr = pKeyPool; + childs[i] = lpTmpPage; + if ( iFirstKey + i >= pPage->iKeys ) + iRet |= NODE_NEWLASTKEY; +#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 ); + iSize += ( iMaxReq - childs[i]->ReqByte ) * 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_UINT32( 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/%d)", pPage->Page, pPage->iKeys, 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 ( iKeys > 0 && ( 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 + { + iMin = HB_MAX( iKeys / iNeedKeys, 2 ); + iMax = HB_MAX( ( iKeys + iNeedKeys - 1 ) / iNeedKeys, iMin ); + 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--; + iMin = HB_MAX( iKeys / iNeedKeys, 2 ); + iMax = HB_MAX( ( iKeys + iNeedKeys - 1 ) / iNeedKeys, iMin ); + } + 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]; + } + iMin = HB_MAX( iKeys / iNeedKeys, 2 ); + iMax = HB_MAX( ( iKeys + iNeedKeys - 1 ) / iNeedKeys, iMin ); + } + } + } + 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_UINT32( 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_cdxPageKeyRemove( LPCDXPAGE pPage ) +{ + int iChildRet; + + if ( pPage->PageType & CDX_NODE_LEAF ) + iChildRet = hb_cdxPageLeafDelKey( pPage ); + else /* interior node */ + iChildRet = hb_cdxPageKeyRemove( 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_UINT32( tagHeader.rootPtr, pTag->RootBlock ); + HB_PUT_LE_UINT16( tagHeader.keySize, pTag->uiLen ); + tagHeader.indexOpt = pTag->OptFlags; + tagHeader.indexSig = 1; + if ( !pTag->AscendKey ) + HB_PUT_LE_UINT16( tagHeader.ascendFlg, 1 ); + + uiKeyLen = pTag->KeyExpr == NULL ? 0 : strlen( pTag->KeyExpr ); + uiForLen = pTag->ForExpr == NULL ? 0 : strlen( pTag->ForExpr ); + + HB_PUT_LE_UINT16( tagHeader.keyExpPos, 0 ); + HB_PUT_LE_UINT16( tagHeader.keyExpLen, uiKeyLen + 1 ); + HB_PUT_LE_UINT16( tagHeader.forExpPos, uiKeyLen + 1 ); + HB_PUT_LE_UINT16( tagHeader.forExpLen, uiForLen + 1 ); + if ( uiKeyLen > 0 ) + { + memcpy( tagHeader.keyExpPool, pTag->KeyExpr, uiKeyLen + 1 ); + } + if ( uiForLen > 0 ) + { + memcpy( tagHeader.keyExpPool + uiKeyLen + 1, pTag->ForExpr, uiForLen + 1 ); + } + 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 tagHeader; + USHORT uiForPos, uiForLen, uiKeyPos, uiKeyLen; + ULONG ulRecNo; + + /* read the page from a file */ + hb_cdxIndexPageRead( pTag->pIndex, pTag->TagBlock, (BYTE *) &tagHeader, sizeof( CDXTAGHEADER ) ); + + uiForPos = HB_GET_LE_UINT16( tagHeader.forExpPos ); + uiForLen = HB_GET_LE_UINT16( tagHeader.forExpLen ); + uiKeyPos = HB_GET_LE_UINT16( tagHeader.keyExpPos ); + uiKeyLen = HB_GET_LE_UINT16( tagHeader.keyExpLen ); + + pTag->RootBlock = HB_GET_LE_UINT32( tagHeader.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 || + ( HB_FOFFSET ) pTag->RootBlock >= hb_fsSeekLarge( pTag->pIndex->hFile, 0, FS_END ) || + HB_GET_LE_UINT16( tagHeader.keySize ) > CDX_MAXKEY || + uiForPos + uiForLen > CDX_HEADEREXPLEN || + uiKeyPos + uiKeyLen > CDX_HEADEREXPLEN ) + { + pTag->RootBlock = 0; /* To force RT error - index corrupted */ + return; + } + pTag->uiLen = HB_GET_LE_UINT16( tagHeader.keySize ); + pTag->MaxKeys = CDX_INT_FREESPACE / ( pTag->uiLen + 8 ); + pTag->OptFlags = tagHeader.indexOpt; + pTag->UniqueKey = ( pTag->OptFlags & CDX_TYPE_UNIQUE ) != 0; + pTag->Temporary = ( pTag->OptFlags & CDX_TYPE_TEMPORARY ) != 0; + pTag->Custom = ( pTag->OptFlags & CDX_TYPE_CUSTOM ) != 0; + pTag->AscendKey = pTag->UsrAscend = ( HB_GET_LE_UINT16( tagHeader.ascendFlg ) == 0 ); + pTag->UsrUnique = FALSE; + pTag->KeyExpr = ( char * ) hb_xgrab( CDX_MAXEXP + 1 ); + hb_strncpyTrim( pTag->KeyExpr, ( const char * ) tagHeader.keyExpPool, CDX_MAXEXP ); + + if ( pTag->OptFlags & CDX_TYPE_STRUCTURE || ! *pTag->KeyExpr ) + return; + + if ( SELF_COMPILE( ( AREAP ) pTag->pIndex->pArea, ( BYTE * ) pTag->KeyExpr ) == FAILURE ) + { + pTag->RootBlock = 0; /* To force RT error - index corrupted */ + return; + } + pTag->pKeyItem = pTag->pIndex->pArea->valResult; + pTag->pIndex->pArea->valResult = NULL; + + /* go to a blank record before testing expression */ + ulRecNo = pTag->pIndex->pArea->ulRecNo; + SELF_GOTO( ( AREAP ) pTag->pIndex->pArea, 0 ); + + pTag->uiType = hb_cdxItemType( hb_vmEvalBlockOrMacro( pTag->pKeyItem ) ); + pTag->bTrail = ( pTag->uiType == 'C' ) ? ' ' : '\0'; + if ( pTag->uiType == 'C' ) + hb_cdxMakeSortTab( pTag->pIndex->pArea ); + + pTag->nField = hb_rddFieldExpIndex( ( AREAP ) pTag->pIndex->pArea, + pTag->KeyExpr ); + + /* Check if there is a FOR expression: pTag->OptFlags & CDX_TYPE_FORFILTER */ + if ( tagHeader.keyExpPool[ uiForPos ] != 0 ) + { + pTag->ForExpr = ( char * ) hb_xgrab( CDX_MAXEXP + 1 ); + hb_strncpyTrim( pTag->ForExpr, ( const char * ) tagHeader.keyExpPool + + uiForPos, CDX_MAXEXP ); + if ( SELF_COMPILE( ( AREAP ) pTag->pIndex->pArea, ( BYTE * ) pTag->ForExpr ) == FAILURE ) + pTag->RootBlock = 0; /* To force RT error - index corrupted */ + else + { + pTag->pForItem = pTag->pIndex->pArea->valResult; + pTag->pIndex->pArea->valResult = NULL; + if ( hb_cdxItemType( hb_vmEvalBlockOrMacro( pTag->pForItem ) ) != 'L' ) + pTag->RootBlock = 0; /* To force RT error - index corrupted */ + } + } + SELF_GOTO( ( AREAP ) pTag->pIndex->pArea, ulRecNo ); + + if ( pTag->uiLen > CDX_MAXKEY || pTag->uiType == 'U' || + ( pTag->uiType == 'N' && pTag->uiLen != 8 ) || + ( pTag->uiType == 'D' && pTag->uiLen != 8 ) || + ( pTag->uiType == 'L' && pTag->uiLen != 1 ) ) + { + pTag->RootBlock = 0; /* To force RT error - index corrupted */ + } +} + +/* + * 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 ) + hb_vmDestroyBlockOrMacro( pTag->pKeyItem ); + if ( pTag->ForExpr != NULL ) + hb_xfree( pTag->ForExpr ); + if ( pTag->pForItem != NULL ) + hb_vmDestroyBlockOrMacro( pTag->pForItem ); + hb_cdxKeyFree( pTag->CurKey ); + if ( pTag->HotKey ) + hb_cdxKeyFree( pTag->HotKey ); + hb_cdxTagClearScope( pTag, 0); + hb_cdxTagClearScope( pTag, 1); + hb_xfree( pTag ); +} + +/* + * 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; + char szName[ CDX_MAXTAGNAMELEN + 1 ]; + + pTag = ( LPCDXTAG ) hb_xgrab( sizeof( CDXTAG ) ); + memset( pTag, 0, sizeof( CDXTAG ) ); + hb_strncpyUpperTrim( szName, szTagName, CDX_MAXTAGNAMELEN ); + pTag->szName = hb_strdup( szName ); + pTag->pIndex = pIndex; + pTag->AscendKey = pTag->UsrAscend = TRUE; + pTag->UsrUnique = FALSE; + pTag->uiType = 'C'; + pTag->bTrail = ' '; + 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 ); + if ( pTag->RootBlock == 0 ) + { + /* index file is corrupted */ + hb_cdxTagFree( pTag ); + pTag = NULL; + } + } + return 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 ); + } + pTag->fRePos = TRUE; +} + +/* + * (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_UINT32( 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\nkeyLen=%d", pPage->TagParent->uiLen); + 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 )); + printf("\r\nparent val=[%s]", hb_cdxPageGetKeyVal( pPage, pPage->iCurKey )); + printf("\r\n child val=[%s]", hb_cdxPageGetKeyVal( 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; +} + +/* + * an interface for fast check record number in record filter + */ +static BOOL hb_cdxCheckRecordScope( CDXAREAP pArea, ULONG ulRec ) +{ + LONG lRecNo = ( LONG ) ulRec; + + if ( SELF_COUNTSCOPE( ( AREAP ) pArea, NULL, &lRecNo ) == SUCCESS && lRecNo == 0 ) + { + return FALSE; + } + return TRUE; +} + +/* + * check and avaluate record filter + */ +static BOOL hb_cdxCheckRecordFilter( CDXAREAP pArea, ULONG ulRecNo ) +{ + BOOL lResult = FALSE; + + if ( pArea->dbfi.fFilter && pArea->dbfi.fOptimized ) + { + if ( BM_GetBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, ulRecNo ) ) + { + if( pArea->ulRecNo != ulRecNo || pArea->lpdbPendingRel ) + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + + if( hb_set.HB_SET_DELETED ) + SUPER_DELETED( ( AREAP ) pArea, &lResult ); + + if( !lResult && pArea->dbfi.itmCobExpr ) + { + PHB_ITEM pResult = hb_vmEvalBlock( pArea->dbfi.itmCobExpr ); + lResult = HB_IS_LOGICAL( pResult ) && !hb_itemGetL( pResult ); + if ( lResult ) + { + LPCDXTAG pTag; + BM_ClrBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, ulRecNo ); + pTag = hb_cdxGetActiveTag( pArea ); + if ( pTag && CURKEY_LOGCNT(pTag) ) + CURKEY_SETLOGCNT( pTag, pTag->logKeyCount - 1 ) + } + } + } + else + lResult = TRUE; + } + else if ( pArea->dbfi.itmCobExpr || hb_set.HB_SET_DELETED ) + { + if( pArea->ulRecNo != ulRecNo || pArea->lpdbPendingRel ) + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + + if( hb_set.HB_SET_DELETED ) + SUPER_DELETED( ( AREAP ) pArea, &lResult ); + + if( !lResult && pArea->dbfi.itmCobExpr ) + { + PHB_ITEM pResult = hb_vmEvalBlock( pArea->dbfi.itmCobExpr ); + lResult = HB_IS_LOGICAL( pResult ) && !hb_itemGetL( pResult ); + } + } + return !lResult; +} + +/* + * 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; + } + + do + { + 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; + } + if( pPage->iCurKey == 0 ) + { + hb_cdxSetCurKey( pPage ); + if( !hb_cdxTopScope( pPage->TagParent ) || + !hb_cdxBottomScope( pPage->TagParent ) ) + break; + } + } + while( !hb_cdxCheckRecordScope( pPage->TagParent->pIndex->pArea, + hb_cdxPageGetKeyRec( pPage, pPage->iCurKey ) ) ); + if( pPage->iCurKey != 0 ) + 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; + } + + do + { + 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; + } + if( pPage->iCurKey == 0 ) + { + hb_cdxSetCurKey( pPage ); + if( !hb_cdxTopScope( pPage->TagParent ) || + !hb_cdxBottomScope( pPage->TagParent ) ) + break; + } + } + while( !hb_cdxCheckRecordScope( pPage->TagParent->pIndex->pArea, + hb_cdxPageGetKeyRec( pPage, pPage->iCurKey ) ) ); + if( 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; + } + } + 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; + + 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->CurKey->rec = 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 BOOL hb_cdxTagKeyAdd( LPCDXTAG pTag, LPCDXKEY pKey ) +{ + hb_cdxTagOpen( pTag ); + if( hb_cdxPageSeekKey( pTag->RootPage, pKey, + pTag->UniqueKey ? CDX_IGNORE_REC_NUM : pKey->rec, + TRUE ) != 0 || ( pTag->Custom && !pTag->UniqueKey ) ) + { + hb_cdxPageKeyInsert( pTag->RootPage, pKey ); + pTag->curKeyState &= ~( CDX_CURKEY_RAWPOS | CDX_CURKEY_LOGPOS | + CDX_CURKEY_RAWCNT | CDX_CURKEY_LOGCNT ); + pTag->fRePos = TRUE; + /* TODO: !!! remove when page leaf balance can save CurKey */ + hb_cdxTagKeyFind( pTag, pKey ); + return TRUE; + } + return FALSE; +} + +/* + * delete the Key from the Tag + */ +static BOOL hb_cdxTagKeyDel( LPCDXTAG pTag, LPCDXKEY pKey ) +{ + if ( hb_cdxTagKeyFind( pTag, pKey ) != 0 ) + { + hb_cdxPageKeyRemove( pTag->RootPage ); + pTag->curKeyState &= ~( CDX_CURKEY_RAWPOS | CDX_CURKEY_LOGPOS | + CDX_CURKEY_RAWCNT | CDX_CURKEY_LOGCNT ); + pTag->CurKey->rec = 0; + return TRUE; + } + return FALSE; +} + +/* + * Go to the first visible record in Tag + */ +static void hb_cdxTagGoTop( LPCDXTAG pTag ) +{ + LPCDXKEY pKey = pTag->UsrAscend ? pTag->topScopeKey : pTag->bottomScopeKey; + ULONG ulPos = 1; + + if ( pKey ) + hb_cdxTagKeyFind( pTag, pKey ); + else + hb_cdxTagKeyRead( pTag, TOP_RECORD ); + + do + { + if ( pTag->CurKey->rec == 0 || pTag->TagEOF || ! hb_cdxBottomScope( pTag ) ) + { + pTag->TagBOF = pTag->TagEOF = TRUE; + pTag->CurKey->rec = 0; + break; + } + else if ( ( pTag->OptFlags & CDX_TYPE_STRUCTURE ) != 0 || + hb_cdxCheckRecordScope( pTag->pIndex->pArea, pTag->CurKey->rec ) ) + { + pTag->rawKeyPos = ulPos; + CURKEY_SETRAWPOS( pTag ); + break; + } + hb_cdxTagKeyRead( pTag, NEXT_RECORD ); + ulPos++; + } + while ( TRUE ); +} + +/* + * Go to the last visible record in Tag + */ +static void hb_cdxTagGoBottom( LPCDXTAG pTag ) +{ + LPCDXKEY pKey = pTag->UsrAscend ? pTag->bottomScopeKey : pTag->topScopeKey; + ULONG ulPos = 0; + + if ( pKey ) + hb_cdxTagKeyFind( pTag, pKey ); + else + hb_cdxTagKeyRead( pTag, BTTM_RECORD ); + + do + { + if ( pTag->CurKey->rec == 0 || pTag->TagBOF || ! hb_cdxTopScope( pTag ) ) + { + pTag->TagBOF = pTag->TagEOF = TRUE; + pTag->CurKey->rec = 0; + break; + } + else if ( ( pTag->OptFlags & CDX_TYPE_STRUCTURE ) != 0 || + hb_cdxCheckRecordScope( pTag->pIndex->pArea, pTag->CurKey->rec ) ) + { + if ( CURKEY_RAWCNT( pTag ) ) + { + pTag->rawKeyPos = pTag->rawKeyCount - ulPos; + CURKEY_SETRAWPOS( pTag ); + } + break; + } + hb_cdxTagKeyRead( pTag, PREV_RECORD ); + ulPos++; + } + while ( TRUE ); +} + +/* + * skip to Next Key in the Tag + */ +static void hb_cdxTagSkipNext( LPCDXTAG pTag ) +{ + BOOL fPos = CURKEY_RAWPOS( pTag ), fEof = FALSE; + ULONG ulSkip = 1; + + if ( pTag->CurKey->rec != 0 ) + { + if ( !hb_cdxTopScope( pTag ) ) + { + ulSkip = 0; + hb_cdxTagGoTop( pTag ); + } + else + hb_cdxTagKeyRead( pTag, NEXT_RECORD ); + } + + while ( !fEof ) + { + if ( pTag->TagEOF || pTag->CurKey->rec == 0 || + !hb_cdxBottomScope( pTag ) || !hb_cdxTopScope( pTag ) ) + fEof = TRUE; + else if ( ( pTag->OptFlags & CDX_TYPE_STRUCTURE ) != 0 || + hb_cdxCheckRecordScope( pTag->pIndex->pArea, pTag->CurKey->rec ) ) + break; + hb_cdxTagKeyRead( pTag, NEXT_RECORD ); + ulSkip++; + } + + if ( fEof ) + { + pTag->CurKey->rec = 0; + pTag->TagEOF = TRUE; + } + else if ( fPos ) + { + pTag->rawKeyPos += ulSkip; + CURKEY_SETRAWPOS( pTag ); + } +} + +/* + * skip to Previous Key in the Tag + */ +static void hb_cdxTagSkipPrev( LPCDXTAG pTag ) +{ + BOOL fPos = CURKEY_RAWPOS( pTag ), fBof = FALSE; + ULONG ulSkip = 1; + + if ( pTag->CurKey->rec == 0 ) + { + ulSkip = 0; + hb_cdxTagGoBottom( pTag ); + } + else + hb_cdxTagKeyRead( pTag, PREV_RECORD ); + + while ( !fBof ) + { + if ( pTag->TagBOF || pTag->CurKey->rec == 0 || + !hb_cdxBottomScope( pTag ) || !hb_cdxTopScope( pTag ) ) + fBof = TRUE; + else if ( ( pTag->OptFlags & CDX_TYPE_STRUCTURE ) != 0 || + hb_cdxCheckRecordScope( pTag->pIndex->pArea, pTag->CurKey->rec ) ) + break; + hb_cdxTagKeyRead( pTag, PREV_RECORD ); + ulSkip++; + } + + + if ( fBof ) + { + hb_cdxTagGoTop( pTag ); + pTag->TagBOF = TRUE; + } + else if ( fPos ) + { + pTag->rawKeyPos -= ulSkip; + CURKEY_SETRAWPOS( pTag ); + } +} + +/* + * 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 LPCDXTAG hb_cdxIndexCreateTag( BOOL fStruct, LPCDXINDEX pIndex, + char * szTagName, + char * KeyExp, PHB_ITEM pKeyItem, + BYTE bType, USHORT uiLen, + char * ForExp, PHB_ITEM pForItem, + BOOL fAscnd, BOOL fUniq, BOOL fCustom, + BOOL fReindex ) +{ + LPCDXTAG pTag; + + pTag = hb_cdxTagNew( pIndex, szTagName, CDX_DUMMYNODE ); + + if ( fStruct ) + pTag->OptFlags |= CDX_TYPE_STRUCTURE; + + if ( bType == 'C' ) + hb_cdxMakeSortTab( pTag->pIndex->pArea ); + if ( KeyExp != NULL ) + { + pTag->KeyExpr = ( char * ) hb_xgrab( CDX_MAXEXP + 1 ); + hb_strncpyTrim( pTag->KeyExpr, KeyExp, CDX_MAXEXP ); + pTag->nField = hb_rddFieldExpIndex( ( AREAP ) pTag->pIndex->pArea, + pTag->KeyExpr ); + } + pTag->pKeyItem = pKeyItem; + if ( ForExp != NULL ) + { + pTag->ForExpr = ( char * ) hb_xgrab( CDX_MAXEXP + 1 ); + hb_strncpyTrim( pTag->ForExpr, ForExp, CDX_MAXEXP ); + } + pTag->pForItem = pForItem; + pTag->AscendKey = pTag->UsrAscend = fAscnd; + pTag->UniqueKey = fUniq; + pTag->UsrUnique = FALSE; + pTag->Custom = fCustom; + pTag->uiType = bType; + pTag->bTrail = ( pTag->uiType == 'C' ) ? ' ' : '\0'; + pTag->uiLen = uiLen; + pTag->MaxKeys = CDX_INT_FREESPACE / ( uiLen + 8 ); + pTag->TagChanged = TRUE; + hb_cdxTagDoIndex( pTag, fReindex ); + + return pTag; +} + +/* + * create structural (compound) tag + */ +static void hb_cdxIndexCreateStruct( LPCDXINDEX pIndex, char * szTagName ) +{ + /* here we can change default tag name */ + pIndex->pCompound = hb_cdxIndexCreateTag( TRUE, pIndex, szTagName, + NULL, NULL, 'C', CDX_MAXTAGNAMELEN, NULL, NULL, + TRUE, FALSE, FALSE, FALSE ); +} + +/* + * 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, pIndex->pCompound->uiLen, + pTag->TagBlock ); + if ( hb_cdxTagKeyDel( pIndex->pCompound, pKey ) ) + { + if ( pTag != pIndex->TagList || pTag->pNext != NULL ) + { + LPCDXPAGE pPage; + + hb_cdxTagOpen( pTag ); + pPage = pTag->RootPage; + hb_cdxTagClose( pTag ); + if ( ! pIndex->fShared ) + { + if ( pPage ) + hb_cdxIndexFreePages( pPage ); + hb_cdxIndexPutAvailPage( pIndex, pTag->TagBlock, TRUE ); + } + pTag->TagChanged = FALSE; + } + } + *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, + BOOL fReindex ) +{ + 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_cdxIndexCreateTag( FALSE, pIndex, szTagName, szKeyExp, pKeyItem, + bType, uiLen, szForExp, pForItem, + fAscend, fUnique, fCustom, fReindex ); + pTagPtr = &pIndex->TagList; + while ( *pTagPtr ) + pTagPtr = &(*pTagPtr)->pNext; + *pTagPtr = pTag; + pKey = hb_cdxKeyPutC( NULL, szTagName, pIndex->pCompound->uiLen, 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 ); + pIndex->fChanged = TRUE; + + /* Rebuild the compound (master) tag */ + if ( pCompound ) + { + hb_cdxIndexCreateStruct( pIndex, pCompound->szName ); + 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, TRUE ); + 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) all tag in index file + */ +static void hb_cdxIndexFreeTags( LPCDXINDEX pIndex ) +{ + LPCDXTAG pTag; + + /* Free Compound tag */ + if ( pIndex->pCompound != NULL ) + { + hb_cdxTagFree( pIndex->pCompound ); + pIndex->pCompound = NULL; + } + + while ( pIndex->TagList ) + { + pTag = pIndex->TagList; + pIndex->TagList = pTag->pNext; + hb_cdxTagFree( pTag ); + } +} + +/* + * free (close) index and all tags in it + */ +static void hb_cdxIndexFree( LPCDXINDEX pIndex ) +{ + /* Free List of Free Pages */ + hb_cdxIndexDropAvailPage( pIndex ); + + /* free all tags */ + hb_cdxIndexFreeTags( pIndex ); + + /* Close file */ + if( pIndex->hFile != FS_ERROR ) + { + hb_fsClose( pIndex->hFile ); + if( pIndex->fDelete ) + { + hb_fsDelete( ( BYTE * ) ( pIndex->szRealName ? + pIndex->szRealName : pIndex->szFileName ) ); + } + } + +#ifdef HB_CDX_DBGCODE + if( pIndex->fShared && ( pIndex->lockWrite || pIndex->lockRead ) && + hb_vmRequestQuery() == 0 ) + hb_errInternal( 9104, "hb_cdxIndexFree: index file still locked.", "", "" ); + + if( ( pIndex->WrLck || pIndex->RdLck ) && + hb_vmRequestQuery() == 0 ) + hb_errInternal( 9104, "hb_cdxIndexFree: index file still locked (*)", "", "" ); +#endif + + if ( pIndex->szFileName != NULL ) + hb_xfree( pIndex->szFileName ); + if( pIndex->szRealName ) + hb_xfree( pIndex->szRealName ); + + hb_xfree( pIndex ); +} + +/* + * load orders from index file + */ +static BOOL hb_cdxIndexLoad( LPCDXINDEX pIndex, char * szBaseName ) +{ + LPCDXTAG TagList, * pTagPtr; + BOOL fResult = FALSE; + + TagList = NULL; + pTagPtr = &TagList; + + hb_cdxIndexLockRead( pIndex ); + /* load the tags*/ + pIndex->pCompound = hb_cdxTagNew( pIndex, szBaseName, 0L ); + + /* check if index is not corrupted */ + if ( pIndex->pCompound ) + { + fResult = TRUE; + pIndex->pCompound->OptFlags = CDX_TYPE_COMPACT | CDX_TYPE_COMPOUND | CDX_TYPE_STRUCTURE; + hb_cdxTagGoTop( pIndex->pCompound ); + while ( !pIndex->pCompound->TagEOF ) + { + *pTagPtr = hb_cdxTagNew( pIndex, (char *) pIndex->pCompound->CurKey->val, + pIndex->pCompound->CurKey->rec ); + /* tag is corrupted - break tags loading */ + if ( *pTagPtr == NULL ) + { + fResult = FALSE; + break; + } + pTagPtr = &(*pTagPtr)->pNext; + hb_cdxTagSkipNext( pIndex->pCompound ); + } + } + + 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 + + return fResult; +} + +/* + * create index file name + */ +static void hb_cdxCreateFName( CDXAREAP pArea, char * szBagName, BOOL * fProd, + char * szFileName, char * szBaseName ) +{ + PHB_FNAME pFileName; + PHB_ITEM pExt = NULL; + BOOL fName = szBagName && *szBagName; + + pFileName = hb_fsFNameSplit( fName ? szBagName : pArea->szDataFileName ); + + if( szBaseName ) + { + if( pFileName->szName ) + hb_strncpyUpperTrim( szBaseName, pFileName->szName, CDX_MAXTAGNAMELEN ); + else + szBaseName[ 0 ] = '\0'; + } + + if( !pFileName->szExtension || !fName ) + { + DBORDERINFO pExtInfo; + memset( &pExtInfo, 0, sizeof( pExtInfo ) ); + pExt = pExtInfo.itmResult = hb_itemPutC( NULL, "" ); + if( SELF_ORDINFO( ( AREAP ) pArea, DBOI_BAGEXT, &pExtInfo ) == SUCCESS && + hb_itemGetCLen( pExt ) > 0 ) + { + pFileName->szExtension = hb_itemGetCPtr( pExt ); + } + } + hb_fsFNameMerge( szFileName, pFileName ); + + if( fProd ) + { + if( ! pFileName->szName ) + *fProd = FALSE; + else if( !fName ) + *fProd = TRUE; + else + { + PHB_FNAME pTableFileName = hb_fsFNameSplit( pArea->szDataFileName ); + + *fProd = pTableFileName->szName && + hb_stricmp( pTableFileName->szName, pFileName->szName ) == 0; + if( *fProd && pFileName->szExtension && ! pExt ) + { + DBORDERINFO pExtInfo; + memset( &pExtInfo, 0, sizeof( pExtInfo ) ); + pExt = pExtInfo.itmResult = hb_itemPutC( NULL, "" ); + if( SELF_ORDINFO( ( AREAP ) pArea, DBOI_BAGEXT, &pExtInfo ) == SUCCESS ) + { + *fProd = hb_stricmp( pFileName->szExtension, + hb_itemGetCPtr( pExt ) ) == 0; + } + } + hb_xfree( pTableFileName ); + } + } + hb_xfree( pFileName ); + if( pExt ) + hb_itemRelease( pExt ); +} + +/* + * 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 ? pFileNameDbf->szName : "", + pFileNameCdx->szName ? pFileNameCdx->szName : "" ) != 0; + if( !fAll ) + { + DBORDERINFO pExtInfo; + PHB_ITEM pExt; + + memset( &pExtInfo, 0, sizeof( pExtInfo ) ); + pExt = pExtInfo.itmResult = hb_itemPutC( NULL, "" ); + if( SELF_ORDINFO( ( AREAP ) pArea, DBOI_BAGEXT, &pExtInfo ) == SUCCESS ) + { + fAll = hb_stricmp( pFileNameCdx->szExtension, + hb_itemGetCPtr( pExt ) ) != 0; + } + hb_itemRelease( pExt ); + } + 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 + */ +static LPCDXINDEX hb_cdxFindBag( CDXAREAP pArea, char * szBagName ) +{ + LPCDXINDEX pIndex; + PHB_FNAME pFileName; + char * szBaseName, * szBasePath, * szBaseExt; + + pFileName = hb_fsFNameSplit( szBagName ); + szBaseName = hb_strdup( pFileName->szName ? pFileName->szName : "" ); + szBasePath = pFileName->szPath ? hb_strdup( pFileName->szPath ) : NULL; + szBaseExt = pFileName->szExtension ? hb_strdup( pFileName->szExtension ) : NULL; + hb_strUpper( szBaseName, strlen(szBaseName) ); + + pIndex = pArea->lpIndexes; + while ( pIndex ) + { + hb_xfree( pFileName ); + pFileName = hb_fsFNameSplit( pIndex->szFileName ); + if ( !hb_stricmp( pFileName->szName ? pFileName->szName : "", szBaseName ) && + ( !szBasePath || + ( pFileName->szPath && !hb_stricmp( pFileName->szPath, szBasePath ) ) ) && + ( !szBaseExt || + ( pFileName->szExtension && !hb_stricmp( pFileName->szExtension, szBaseExt ) ) ) ) + break; + pIndex = pIndex->pNext; + } + hb_xfree( pFileName ); + hb_xfree( szBaseName ); + if ( szBasePath ) + hb_xfree( szBasePath ); + if ( szBaseExt ) + hb_xfree( szBaseExt ); + 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 pIndex = pArea->lpIndexes; + + if ( pFindTag ) + { + while ( pIndex && ( pTag != pFindTag ) ) + { + pTag = pIndex->TagList; + while ( pTag ) + { + uiTag++; + if ( pTag == pFindTag ) + break; + pTag = pTag->pNext; + } + pIndex = pIndex->pNext; + } + if ( !pTag ) + uiTag = 0; + } + return uiTag; +} + +/* + * find Tag in tag list + */ +static LPCDXTAG hb_cdxFindTag( CDXAREAP pArea, PHB_ITEM pTagItem, + PHB_ITEM pBagItem, USHORT *puiTag ) +{ + LPCDXTAG pTag = NULL; + int iTag = 0, iFind = 0; + char szTag[ CDX_MAXTAGNAMELEN + 1 ]; + LPCDXINDEX pIndex = pArea->lpIndexes; + BOOL fBag; + + hb_strncpyUpperTrim( szTag, hb_itemGetCPtr( pTagItem ), CDX_MAXTAGNAMELEN ); + if( ! szTag[0] ) + iFind = hb_itemGetNI( pTagItem ); + + fBag = hb_itemGetCLen( pBagItem ) > 0; + if( fBag ) + { + if( szTag[ 0 ] ) + pIndex = hb_cdxFindBag( pArea, hb_itemGetCPtr( pBagItem ) ); + } + else + { + int iBag = hb_itemGetNI( pBagItem ); + + if( iBag > 0 ) + { + fBag = TRUE; + while( pIndex ) + { + if( --iBag == 0 ) + break; + pIndex = pIndex->pNext; + } + } + else if( iBag < 0 ) + { + pIndex = NULL; + } + } + + if( pIndex && ( iFind > 0 || szTag[0] ) ) + { + do + { + pTag = pIndex->TagList; + while( pTag ) + { + iTag++; + if ( ( iFind != 0 ? iTag == iFind : !hb_stricmp( pTag->szName, szTag ) ) ) + break; + pTag = pTag->pNext; + } + if ( pTag || fBag ) + break; + pIndex = pIndex->pNext; + } while ( pIndex ); + } + + if( puiTag ) + { + if( !pTag ) + *puiTag = 0; + else if( fBag ) + *puiTag = hb_cdxGetTagNumber( pArea, pTag ); + else + *puiTag = iTag; + } + + return pTag; +} + +/* + * 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 + */ +static BOOL hb_cdxCurKeyRefresh( CDXAREAP pArea, LPCDXTAG pTag ) +{ + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + if ( !pArea->fPositioned ) + { + pTag->TagEOF = TRUE; + pTag->fRePos = FALSE; + pTag->CurKey->rec = 0; + return FALSE; + } + else if ( pTag->fRePos || pTag->CurKey->rec != pArea->ulRecNo ) + { + BYTE buf[CDX_MAXKEY]; + BOOL fBuf = FALSE; + LPCDXKEY pKey = NULL; + + /* Try to find previous if it's key for the same record */ + if ( pTag->CurKey->rec == pArea->ulRecNo ) + { + fBuf = TRUE; + memcpy( buf, pTag->CurKey->val, pTag->CurKey->len ); + pKey = hb_cdxKeyCopy( pKey, pTag->CurKey ); + hb_cdxTagKeyFind( pTag, pKey ); + } + if ( pTag->CurKey->rec != pArea->ulRecNo ) + { + BOOL fValidBuf = pArea->fValidBuffer; + /* not found, create new key from DBF and if differs seek again */ + pKey = hb_cdxKeyEval( pKey, pTag ); + if ( !fBuf || memcmp( buf, pKey->val, pKey->len ) != 0 ) + { + hb_cdxTagKeyFind( pTag, pKey ); + } + /* not found, if key was generated from DBF buffer then force to + * update it, create the new key and if differs seek again */ + if ( pTag->CurKey->rec != pArea->ulRecNo && fValidBuf ) + { + SELF_GOTO( ( AREAP ) pArea, pArea->ulRecNo ); + memcpy( buf, pKey->val, pKey->len ); + pKey = hb_cdxKeyEval( pKey, pTag ); + if ( memcmp( buf, pKey->val, pKey->len ) != 0 ) + hb_cdxTagKeyFind( pTag, pKey ); + } + } + hb_cdxKeyFree( pKey ); + return ( pTag->CurKey->rec != 0 && pTag->CurKey->rec == pArea->ulRecNo ); + } + return TRUE; +} + +/* + * skip to next/previous unique key + */ +static ERRCODE hb_cdxDBOISkipUnique( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward ) +{ + ERRCODE retval; + + HB_TRACE(HB_TR_DEBUG, ("hb_cdxDBOISkipUnique(%p, %p, %i)", pArea, pTag, fForward)); + + if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + if ( ! pTag ) + return SELF_SKIP( ( AREAP ) pArea, fForward ? 1 : -1 ); + + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + pArea->fTop = pArea->fBottom = FALSE; + + if ( !pArea->fPositioned ) + { + if ( fForward ) + retval = SELF_GOTO( ( AREAP ) pArea, 0 ); + else + retval = SELF_GOBOTTOM( ( AREAP ) pArea ); + } + else + { + LPCDXKEY pKey = NULL; + BOOL fOut = FALSE; + + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + if ( ! hb_cdxCurKeyRefresh( pArea, pTag ) ) + { + if ( pTag->TagEOF || ( fForward ? !hb_cdxBottomScope( pTag ) : + !hb_cdxTopScope( pTag ) ) ) + fOut = TRUE; + else if ( ( fForward ? pTag->UsrAscend && hb_cdxTopScope( pTag ) : + !pTag->UsrAscend && hb_cdxBottomScope( pTag ) ) && + pTag->CurKey->rec != 0 ) + { + pKey = hb_cdxKeyEval( pKey, pTag ); + } + } + if ( fForward ) + { + if ( pArea->fPositioned && !pTag->TagEOF ) + { + if ( !pKey ) + { + pKey = hb_cdxKeyCopy( NULL, pTag->CurKey ); + hb_cdxTagSkipNext( pTag ); + } + while ( !pTag->TagEOF ) + { + if ( hb_cdxValCompare( pTag, pKey->val, pKey->len, + pTag->CurKey->val, pTag->CurKey->len, TRUE ) != 0 ) + { + SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec ); + SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); + break; + } + hb_cdxTagSkipNext( pTag ); + } + } + retval = SELF_GOTO( ( AREAP ) pArea, ( !pArea->fPositioned || pTag->TagEOF ) + ? 0 : pTag->CurKey->rec ); + } + else + { + if ( !fOut && !pTag->TagBOF ) + { + if ( !pKey ) + { + pKey = hb_cdxKeyCopy( NULL, pTag->CurKey ); + hb_cdxTagSkipPrev( pTag ); + } + while ( !pTag->TagBOF ) + { + if ( hb_cdxValCompare( pTag, pKey->val, pKey->len, + pTag->CurKey->val, pTag->CurKey->len, TRUE ) != 0 ) + { + SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec ); + SELF_SKIPFILTER( ( AREAP ) pArea, -1 ); + break; + } + hb_cdxTagSkipPrev( pTag ); + } + } + + 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 ); + if ( pKey ) + hb_cdxKeyFree( pKey ); + } + /* 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, fFirst = TRUE; + + HB_TRACE(HB_TR_DEBUG, ("hb_cdxDBOISkipEval(%p, %p, %i, %p)", pArea, pTag, fForward, pEval)); + + if( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FALSE; + + if( ! pTag || hb_itemType( pEval ) != HB_IT_BLOCK ) + { + if( SELF_SKIP( ( AREAP ) pArea, fForward ? 1 : -1 ) == FAILURE ) + return FALSE; + return fForward ? !pArea->fEof : !pArea->fBof; + } + + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + pArea->fTop = pArea->fBottom = FALSE; + + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + if ( ! hb_cdxCurKeyRefresh( pArea, pTag ) ) + { + if ( !pTag->TagEOF && pTag->CurKey->rec != 0 && + ( fForward ? pTag->UsrAscend : !pTag->UsrAscend ) && + hb_cdxTopScope( pTag ) && hb_cdxBottomScope( pTag ) ) + fFirst = FALSE; + } + if ( fForward ) + { + if ( fFirst ) + hb_cdxTagSkipNext( pTag ); + while ( !pTag->TagEOF ) + { + if ( SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec ) == FAILURE ) + break; + if ( hb_cdxEvalSeekCond( pTag, pEval ) ) + { + ULONG ulRecNo = pArea->ulRecNo; + SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); + if ( pArea->ulRecNo == ulRecNo || hb_cdxEvalSeekCond( pTag, pEval ) ) + { + fFound = TRUE; + break; + } + } + hb_cdxTagSkipNext( pTag ); + } + if ( !fFound ) + SELF_GOTO( ( AREAP ) pArea, 0 ); + } + else + { + if ( fFirst ) + hb_cdxTagSkipPrev( pTag ); + while ( !pTag->TagBOF ) + { + if ( SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec ) == FAILURE ) + break; + if ( hb_cdxEvalSeekCond( pTag, pEval ) ) + { + ULONG ulRecNo = pArea->ulRecNo; + SELF_SKIPFILTER( ( AREAP ) pArea, -1 ); + if ( pArea->ulRecNo == ulRecNo || hb_cdxEvalSeekCond( pTag, pEval ) ) + { + fFound = TRUE; + break; + } + } + hb_cdxTagSkipPrev( pTag ); + } + 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; +} + +/* + * skip while comparison with given pattern with wildcards doesn't return TRUE + */ +static BOOL hb_cdxDBOISkipWild( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward, + PHB_ITEM pWildItm ) +{ + BOOL fFound = FALSE, fFirst = TRUE; + char *szPattern = hb_itemGetCPtr( pWildItm ); + int iFixed = 0, iStop; + + HB_TRACE(HB_TR_DEBUG, ("hb_cdxDBOISkipWild(%p, %p, %i, %p)", pArea, pTag, fForward, pWildItm)); + + if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FALSE; + + if ( ! pTag || pTag->uiType != 'C' || !szPattern || !*szPattern ) + { + if ( SELF_SKIP( ( AREAP ) pArea, fForward ? 1 : -1 ) == FAILURE ) + return FALSE; + return fForward ? pArea->fPositioned : !pArea->fBof; + } + +#ifndef HB_CDP_SUPPORT_OFF + if( pArea->cdPage != hb_cdp_page ) + { + szPattern = hb_strdup( szPattern ); + hb_cdpTranslate( szPattern, hb_cdp_page, pArea->cdPage ); + } +#endif + while( iFixed < pTag->uiLen && szPattern[ iFixed ] && + szPattern[ iFixed ] != '*' && szPattern[ iFixed ] != '?' ) + { + ++iFixed; + } + + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + pArea->fTop = pArea->fBottom = FALSE; + + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + if ( ! hb_cdxCurKeyRefresh( pArea, pTag ) ) + { + if ( !pTag->TagEOF && pTag->CurKey->rec != 0 && + ( fForward ? pTag->UsrAscend : !pTag->UsrAscend ) && + hb_cdxTopScope( pTag ) && hb_cdxBottomScope( pTag ) ) + fFirst = FALSE; + } + + iStop = pTag->UsrAscend ? -1 : 1; + if( !fForward ) + iStop = -iStop; + + if( iFixed && !pTag->TagEOF && pTag->CurKey->rec != 0 && + hb_cdxValCompare( pTag, ( BYTE * ) szPattern, iFixed, + pTag->CurKey->val, iFixed, FALSE ) == -iStop ) + { + LPCDXKEY pKey; + + pKey = hb_cdxKeyPut( NULL, ( BYTE * ) szPattern, iFixed, + pTag->UsrAscend ? CDX_IGNORE_REC_NUM : CDX_MAX_REC_NUM ); + if( !hb_cdxTagKeyFind( pTag, pKey ) ) + { + if( fForward ) + pTag->TagEOF = TRUE; + else + pTag->TagBOF = TRUE; + } + hb_cdxKeyFree( pKey ); + fFirst = FALSE; + } + + if ( fForward ) + { + if ( fFirst ) + hb_cdxTagSkipNext( pTag ); + while ( !pTag->TagEOF ) + { + if ( hb_strMatchWild( (const char *) pTag->CurKey->val, szPattern ) ) + { + ULONG ulRecNo = pTag->CurKey->rec; + if( SELF_GOTO( ( AREAP ) pArea, ulRecNo ) != SUCCESS ) + break; + SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); + if ( pArea->ulRecNo == ulRecNo || + hb_strMatchWild( (const char *) pTag->CurKey->val, szPattern ) ) + { + fFound = TRUE; + break; + } + } + if( iFixed && hb_cdxValCompare( pTag, ( BYTE * ) szPattern, iFixed, + pTag->CurKey->val, iFixed, FALSE ) == iStop ) + { + break; + } + hb_cdxTagSkipNext( pTag ); + } + if( !fFound ) + SELF_GOTO( ( AREAP ) pArea, 0 ); + } + else + { + if ( fFirst ) + hb_cdxTagSkipPrev( pTag ); + while ( !pTag->TagBOF ) + { + if ( hb_strMatchWild( (const char *) pTag->CurKey->val, szPattern ) ) + { + ULONG ulRecNo = pTag->CurKey->rec; + if( SELF_GOTO( ( AREAP ) pArea, ulRecNo ) != SUCCESS ) + break; + SELF_SKIPFILTER( ( AREAP ) pArea, -1 ); + if ( pArea->ulRecNo == ulRecNo || + hb_strMatchWild( (const char *) pTag->CurKey->val, szPattern ) ) + { + fFound = TRUE; + break; + } + } + if( iFixed && hb_cdxValCompare( pTag, ( BYTE * ) szPattern, iFixed, + pTag->CurKey->val, iFixed, FALSE ) == iStop ) + { + break; + } + hb_cdxTagSkipPrev( pTag ); + } + 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; + +#ifndef HB_CDP_SUPPORT_OFF + if( pArea->cdPage != hb_cdp_page ) + { + hb_xfree( szPattern ); + } +#endif + + return fFound; +} + +static BOOL hb_cdxRegexMatch( CDXAREAP pArea, PHB_REGEX pRegEx, LPCDXKEY pKey ) +{ + char * szKey = ( char * ) pKey->val; +#ifndef HB_CDP_SUPPORT_OFF + char szBuff[ CDX_MAXKEY + 1 ]; + + if( pArea->cdPage != hb_cdp_page ) + { + hb_strncpy( szBuff, szKey, pKey->len ); + hb_cdpnTranslate( szBuff, pArea->cdPage, hb_cdp_page, pKey->len ); + szKey = szBuff; + } +#else + HB_SYMBOL_UNUSED( pArea ); +#endif + return hb_regexMatch( pRegEx, szKey, FALSE ); +} + +/* + * skip while regular expression on index key val doesn't return TRUE + */ +static BOOL hb_cdxDBOISkipRegEx( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward, + PHB_ITEM pRegExItm ) +{ + BOOL fFound = FALSE, fFirst = TRUE; + PHB_REGEX pRegEx; + + HB_TRACE(HB_TR_DEBUG, ("hb_cdxDBOISkipRegEx(%p, %p, %i, %p)", pArea, pTag, fForward, pRegExItm)); + + if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FALSE; + + if( !pTag || pTag->uiType != 'C' || ( pRegEx = hb_regexGet( pRegExItm, 0 ) ) == NULL ) + { + if ( SELF_SKIP( ( AREAP ) pArea, fForward ? 1 : -1 ) == FAILURE ) + return FALSE; + return fForward ? pArea->fPositioned : !pArea->fBof; + } + + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + pArea->fTop = pArea->fBottom = FALSE; + + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + if ( ! hb_cdxCurKeyRefresh( pArea, pTag ) ) + { + if ( !pTag->TagEOF && pTag->CurKey->rec != 0 && + ( fForward ? pTag->UsrAscend : !pTag->UsrAscend ) && + hb_cdxTopScope( pTag ) && hb_cdxBottomScope( pTag ) ) + fFirst = FALSE; + } + if ( fForward ) + { + if ( fFirst ) + hb_cdxTagSkipNext( pTag ); + while ( !pTag->TagEOF ) + { + if( hb_cdxRegexMatch( pArea, pRegEx, pTag->CurKey ) ) + { + ULONG ulRecNo = pArea->ulRecNo; + SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); + if ( pArea->ulRecNo == ulRecNo || + hb_cdxRegexMatch( pArea, pRegEx, pTag->CurKey ) ) + { + fFound = TRUE; + break; + } + } + hb_cdxTagSkipNext( pTag ); + } + SELF_GOTO( ( AREAP ) pArea, fFound ? pTag->CurKey->rec : 0 ); + } + else + { + if ( fFirst ) + hb_cdxTagSkipPrev( pTag ); + while ( !pTag->TagBOF ) + { + if( hb_cdxRegexMatch( pArea, pRegEx, pTag->CurKey ) ) + { + ULONG ulRecNo = pArea->ulRecNo; + SELF_SKIPFILTER( ( AREAP ) pArea, -1 ); + if ( pArea->ulRecNo == ulRecNo || + hb_cdxRegexMatch( pArea, pRegEx, pTag->CurKey ) ) + { + fFound = TRUE; + break; + } + } + hb_cdxTagSkipPrev( pTag ); + } + if ( fFound ) + SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec ); + else + { + 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; + + hb_regexFree( pRegEx ); + + return fFound; +} + +/* + * evaluate given C function in given scope + */ +static ULONG hb_cdxDBOIScopeEval( LPCDXTAG pTag, HB_EVALSCOPE_FUNC pFunc, void *pParam, PHB_ITEM pItemLo, PHB_ITEM pItemHi ) +{ + ULONG ulCount = 0, ulLen = ( ULONG ) pTag->uiLen; + LPCDXKEY pCurKey = hb_cdxKeyCopy( NULL, pTag->CurKey ), + pTopScopeKey = pTag->topScopeKey, + pBtmScopeKey = pTag->bottomScopeKey; + + /* TODO: RT error when item type differ then Tag type */ + if ( !pItemLo || HB_IS_NIL( pItemLo ) ) + pTag->topScopeKey = NULL; + else + pTag->topScopeKey = hb_cdxKeyPutItem( NULL, pItemLo, CDX_IGNORE_REC_NUM, pTag, TRUE, FALSE ); + + if ( !pItemHi || HB_IS_NIL( pItemHi ) ) + pTag->bottomScopeKey = NULL; + else + pTag->bottomScopeKey = hb_cdxKeyPutItem( NULL, pItemHi, CDX_MAX_REC_NUM, pTag, TRUE, FALSE ); + + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagGoTop( pTag ); + while( !pTag->TagEOF ) + { + pFunc( pTag->CurKey->rec, pTag->CurKey->val, ulLen, pParam ); + ulCount++; + hb_cdxTagSkipNext( pTag ); + } + hb_cdxIndexUnLockRead( pTag->pIndex ); + + if ( pTag->topScopeKey ) + hb_cdxKeyFree( pTag->topScopeKey ); + pTag->topScopeKey = pTopScopeKey; + if ( pTag->bottomScopeKey ) + hb_cdxKeyFree( pTag->bottomScopeKey ); + pTag->bottomScopeKey = pBtmScopeKey; + pTag->curKeyState &= ~( CDX_CURKEY_RAWPOS | CDX_CURKEY_LOGPOS ); + + pTag->fRePos = TRUE; + hb_cdxKeyCopy( pTag->CurKey, pCurKey ); + hb_cdxKeyFree( pCurKey ); + + return ulCount; +} + +/* + * return number of keys in order + */ +static LONG hb_cdxDBOIKeyCount( CDXAREAP pArea, LPCDXTAG pTag, BOOL fFilters ) +{ + ULONG ulKeyCount = 0; + BOOL fLogOpt = pArea->dbfi.itmCobExpr || !pArea->dbfi.fFilter; + + if ( pTag ) + { + BOOL fCheckFilter = ( fLogOpt && fFilters && pArea->dbfi.itmCobExpr ); + ULONG ulRecNo = pArea->ulRecNo; + LPCDXKEY pCurKey; + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + + if ( pTag && ( fFilters ? fLogOpt && CURKEY_LOGCNT( pTag ) : CURKEY_RAWCNT( pTag ) ) ) + { + ulKeyCount = fFilters ? pTag->logKeyCount : pTag->rawKeyCount; + } + else + { + if ( pTag->topScopeKey || pTag->bottomScopeKey || pTag->UsrUnique || pArea->dbfi.fFilter ) + { + pCurKey = hb_cdxKeyCopy( NULL, pTag->CurKey ); + hb_cdxTagGoTop( pTag ); + while ( !pTag->TagEOF ) + { + if ( !fCheckFilter || hb_cdxCheckRecordFilter( pArea, pTag->CurKey->rec ) ) + ulKeyCount++; + hb_cdxTagSkipNext( pTag ); + } + pTag->fRePos = TRUE; + hb_cdxKeyCopy( pTag->CurKey, pCurKey ); + hb_cdxKeyFree( pCurKey ); + if ( fCheckFilter ) + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + } + else + { + LPCDXPAGE pPage; + pCurKey = hb_cdxKeyCopy( NULL, pTag->CurKey ); + if ( pTag->UsrAscend ) + hb_cdxTagGoTop( pTag ); + else + hb_cdxTagGoBottom( pTag ); + pPage = pTag->RootPage; + while ( pPage->Child ) + pPage = pPage->Child; + ulKeyCount = 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 ); + ulKeyCount += pPage->iKeys; + pPage->Page = pPage->Right; + } + hb_cdxPageFree( pPage, TRUE ); + } + pTag->fRePos = TRUE; + hb_cdxKeyCopy( pTag->CurKey, pCurKey ); + hb_cdxKeyFree( pCurKey ); + } + if ( !fFilters ) + { + pTag->rawKeyCount = ulKeyCount; + pTag->curKeyState |= CDX_CURKEY_RAWCNT; + } + else if ( fLogOpt ) + CURKEY_SETLOGCNT( pTag, ulKeyCount ) + + } + hb_cdxIndexUnLockRead( pTag->pIndex ); + } + else /* no filter, no order */ + { + if ( fLogOpt && fFilters && pArea->dbfi.itmCobExpr ) + { + ULONG ulRecNo = pArea->ulRecNo; + + if ( SELF_GOTOP( ( AREAP ) pArea ) == SUCCESS ) + { + while ( !pArea->fEof ) + { + ulKeyCount++; + if ( SELF_SKIP( ( AREAP ) pArea, 1 ) != SUCCESS ) + break; + } + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + } + } + else + { + SELF_RECCOUNT( ( AREAP ) pArea, &ulKeyCount ); + } + } + return ulKeyCount; +} + +/* + * return logical key position in order + */ +static LONG hb_cdxDBOIKeyNo( CDXAREAP pArea, LPCDXTAG pTag, BOOL fFilters ) +{ + ULONG ulKeyNo = 0; + BOOL fLogOpt = pArea->dbfi.itmCobExpr || !pArea->dbfi.fFilter; + + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + if ( !pArea->fPositioned ) + ulKeyNo = 0; + else if ( pTag ) + { + BOOL fCheckFilter = ( fLogOpt && fFilters && pArea->dbfi.itmCobExpr ); + ULONG ulRecNo = pArea->ulRecNo; + + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + + if ( fFilters ? ( fLogOpt && CURKEY_LOGPOS( pTag ) ) : + ( CURKEY_RAWPOS( pTag ) && + pTag->rawKeyRec == pArea->ulRecNo ) ) + { + ulKeyNo = fFilters ? pTag->logKeyPos : pTag->rawKeyPos; + } + else + { + hb_cdxTagOpen( pTag ); + if ( hb_cdxCurKeyRefresh( pArea, pTag ) ) + { + if ( pTag->topScopeKey || pTag->bottomScopeKey || pTag->UsrUnique || pArea->dbfi.fFilter ) + { + if ( hb_cdxBottomScope( pTag ) && hb_cdxTopScope( pTag ) && + ( !fCheckFilter || hb_cdxCheckRecordFilter( pArea, ulRecNo ) ) ) + { + LPCDXKEY pCurKey = hb_cdxKeyCopy( NULL, pTag->CurKey ); + if ( !hb_cdxCheckRecordScope( pArea, pTag->CurKey->rec ) ) + hb_cdxTagSkipPrev( pTag ); + while ( !pTag->TagBOF ) + { + if ( !fCheckFilter || hb_cdxCheckRecordFilter( pArea, pTag->CurKey->rec ) ) + ulKeyNo++; + hb_cdxTagSkipPrev( pTag ); + } + pTag->fRePos = TRUE; + hb_cdxKeyCopy( pTag->CurKey, pCurKey ); + hb_cdxKeyFree( pCurKey ); + if ( fCheckFilter ) + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + } + } + else + { + LPCDXPAGE pPage = pTag->RootPage; + while ( pPage->Child ) + pPage = pPage->Child; + if ( pTag->UsrAscend ) + { + ulKeyNo = 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 ); + ulKeyNo += pPage->iKeys; + pPage->Page = pPage->Left; + } + hb_cdxPageFree( pPage, TRUE ); + } + } + else + { + ulKeyNo = 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 ); + ulKeyNo += pPage->iKeys; + pPage->Page = pPage->Right; + } + hb_cdxPageFree( pPage, TRUE ); + } + } + } + if ( ulKeyNo != 0 ) + { + if ( !fFilters ) + { + pTag->rawKeyPos = ulKeyNo; + CURKEY_SETRAWPOS( pTag ); + } + else if ( fLogOpt ) + { + pTag->logKeyPos = ulKeyNo; + CURKEY_SETLOGPOS( pTag ); + } + } + } + } + hb_cdxIndexUnLockRead( pTag->pIndex ); + } + else + { + ULONG ulRecNo = pArea->ulRecNo; + + if ( fLogOpt && fFilters && pArea->dbfi.itmCobExpr ) + { + if ( hb_cdxCheckRecordFilter( pArea, ulRecNo ) ) + { + do + { + ulKeyNo++; + if ( SELF_SKIP( ( AREAP ) pArea, -1 ) != SUCCESS ) + break; + } while ( !( ( AREAP ) pArea )->fBof ); + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + } + } + else + { + ulKeyNo = ulRecNo; + } + } + return ulKeyNo; +} + +/* + * DBOI_KEYGOTO goto specific logical record in the index file + */ +static ERRCODE hb_cdxDBOIKeyGoto( CDXAREAP pArea, LPCDXTAG pTag, ULONG ulKeyNo, BOOL fFilters ) +{ + ERRCODE retval; + ULONG ulKeyCnt = ulKeyNo; + BOOL fLogOpt = pArea->dbfi.itmCobExpr || !pArea->dbfi.fFilter; + + if ( ulKeyNo == 0 ) + retval = SELF_GOTO( ( AREAP ) pArea, 0 ); + else if ( pTag ) + { + BOOL fCheckFilter = ( fLogOpt && fFilters && pArea->dbfi.itmCobExpr ); + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + if ( ! pArea->lpdbPendingRel && ( fFilters ? + fLogOpt && CURKEY_LOGPOS( pTag ) && pTag->logKeyPos == ulKeyNo : + ( CURKEY_RAWPOS( pTag ) && pTag->rawKeyPos == ulKeyNo ) ) ) + { + retval = SELF_GOTO( ( AREAP ) pArea, fFilters ? pTag->logKeyRec : pTag->rawKeyRec ); + } + else + { + if ( pTag->topScopeKey || pTag->bottomScopeKey || pTag->UsrUnique || pArea->dbfi.fFilter ) + { + hb_cdxTagGoTop( pTag ); + if ( fCheckFilter ) + while ( !pTag->TagEOF ) + { + if ( hb_cdxCheckRecordFilter( pArea, pTag->CurKey->rec ) ) + { + if ( ! --ulKeyCnt ) + break; + } + hb_cdxTagSkipNext( pTag ); + } + else + while( !pTag->TagEOF && --ulKeyCnt ) + hb_cdxTagSkipNext( pTag ); + } + else + { + LPCDXPAGE pPage, pOwnerPage = NULL; + ULONG ulNextPg; + hb_cdxTagGoTop( pTag ); + pPage = pTag->RootPage; + while ( pPage->Child ) + { + pOwnerPage = pPage; + pPage = pPage->Child; + } + while ( (ULONG) pPage->iKeys < ulKeyCnt && pOwnerPage && + ( ulNextPg = pTag->UsrAscend ? + pPage->Right : pPage->Left ) != CDX_DUMMYNODE ) + { + ulKeyCnt -= pPage->iKeys; + pOwnerPage->Child = hb_cdxPageNew( pPage->TagParent, pPage->Owner, ulNextPg ); + hb_cdxPageFree( pPage, FALSE ); + pPage = pOwnerPage->Child; + } + if ( (ULONG) pPage->iKeys >= ulKeyCnt ) + { + pPage->iCurKey = pTag->UsrAscend ? ( SHORT ) ulKeyCnt - 1 : pPage->iKeys - ( SHORT ) ulKeyCnt; + hb_cdxSetCurKey( pPage ); + } + else + { + pTag->CurKey->rec = 0; + } + } + retval = SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec ); + if ( pArea->fPositioned ) + { + if ( !fFilters ) + { + pTag->rawKeyPos = ulKeyNo; + CURKEY_SETRAWPOS( pTag ); + } + else if ( fLogOpt ) + { + pTag->logKeyPos = ulKeyNo; + CURKEY_SETLOGPOS( pTag ); + } + } + } + hb_cdxIndexUnLockRead( pTag->pIndex ); + } + else + { + if ( fLogOpt && fFilters && pArea->dbfi.itmCobExpr ) + { + retval = SELF_GOTOP( ( AREAP ) pArea ); + if( retval == SUCCESS && --ulKeyCnt ) + retval = SELF_SKIP( ( AREAP ) pArea, ulKeyCnt ); + } + else + { + retval = SELF_GOTO( ( AREAP ) pArea, ulKeyNo ); + } + } + + return retval; +} + +static double hb_cdxCountRelKeyPos( LPCDXPAGE pPage ) +{ + return ( ( pPage->Child ? hb_cdxCountRelKeyPos( pPage->Child ) : 0.5 ) + + pPage->iCurKey ) / pPage->iKeys; +} + +static BOOL hb_cdxGoToRelKeyPos( LPCDXPAGE pPage, double dPos ) +{ + do + { + if( pPage->iKeys == 0 ) + return FALSE; + + pPage->iCurKey = ( SHORT ) ( dPos * pPage->iKeys ); + if( pPage->iCurKey >= pPage->iKeys ) + pPage->iCurKey = pPage->iKeys - 1; + + if( ( pPage->PageType & CDX_NODE_LEAF ) != 0 ) + break; + + dPos = dPos * pPage->iKeys - pPage->iCurKey; + if( dPos < 0.0 ) + dPos = 0.0; + else if( dPos >= 1.0 ) + dPos = 1.0; + + hb_cdxPageGetChild( pPage ); + pPage = pPage->Child; + } + while( pPage ); + + return TRUE; +} + +static double hb_cdxDBOIGetRelKeyPos( CDXAREAP pArea, LPCDXTAG pTag ) +{ + ULONG ulRecNo = 0, ulRecCount = 0; + double dPos = 0.0; + + /* resolve any pending relations */ + SELF_RECNO( ( AREAP ) pArea, &ulRecNo ); + + if( !pArea->fPositioned ) + { + if( ulRecNo > 1 ) + dPos = 1.0; + } + else if( !pTag ) + { + SELF_RECCOUNT( ( AREAP ) pArea, &ulRecCount ); + if( ulRecCount != 0 ) + dPos = ( 0.5 + ulRecNo ) / ulRecCount; + } + else + { + LPCDXKEY pKey; + double dStart, dStop, dFact = 0.0000000000001; + BOOL fOK = TRUE; + + if( pTag->UsrAscend ) + { + dStart = 0.0; + dStop = 1.0; + } + else + { + dStart = 1.0; + dStop = 0.0; + } + + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + + pKey = pTag->UsrAscend ? pTag->topScopeKey : pTag->bottomScopeKey; + if( pKey ) + { + hb_cdxTagKeyFind( pTag, pKey ); + if( pTag->CurKey->rec == 0 || pTag->TagEOF || ! hb_cdxBottomScope( pTag ) ) + fOK = FALSE; + else + dStart = hb_cdxCountRelKeyPos( pTag->RootPage ); + } + pKey = pTag->UsrAscend ? pTag->bottomScopeKey : pTag->topScopeKey; + if( pKey && fOK ) + { + hb_cdxTagKeyFind( pTag, pKey ); + if( pTag->CurKey->rec == 0 || pTag->TagBOF || ! hb_cdxTopScope( pTag ) ) + fOK = FALSE; + else + dStop = hb_cdxCountRelKeyPos( pTag->RootPage ); + } + if( fOK ) + { + if( !pTag->UsrAscend ) + { + double dTmp = dStart; + dStart = dStop; + dStop = dTmp; + } + pTag->fRePos = TRUE; + if( hb_cdxCurKeyRefresh( pArea, pTag ) && + hb_cdxTopScope( pTag ) && hb_cdxBottomScope( pTag ) ) + { + if( dStart >= dStop - dFact ) + dPos = 0.5; + else + { + dPos = hb_cdxCountRelKeyPos( pTag->RootPage ); + dPos = ( dPos - dStart ) / ( dStop - dStart ); + if( !pTag->UsrAscend ) + dPos = 1.0 - dPos; + /* fix possible differences in FL representation */ + if( dPos <= 0.0 ) + dPos = 0.0; + else if( dPos >= 1.0 ) + dPos = 1.0; + } + } + } + hb_cdxIndexUnLockRead( pTag->pIndex ); + } + + return dPos; +} + +static void hb_cdxDBOISetRelKeyPos( CDXAREAP pArea, LPCDXTAG pTag, double dPos ) +{ + if( !pTag ) + { + if( dPos >= 1.0 ) + { + SELF_GOBOTTOM( ( AREAP ) pArea ); + } + else if( dPos <= 0.0 ) + { + SELF_GOTOP( ( AREAP ) pArea ); + } + else + { + ULONG ulRecCount, ulRecNo; + SELF_RECCOUNT( ( AREAP ) pArea, &ulRecCount ); + ulRecNo = ( ULONG ) dPos * ulRecCount + 1; + if( ulRecNo >= ulRecCount ) + ulRecNo = ulRecCount; + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); + if( pArea->fEof ) + SELF_GOTOP( ( AREAP ) pArea ); + } + } + else + { + BOOL fForward = TRUE, fOK = TRUE, fTop = FALSE; + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + + if( dPos >= 1.0 ) + { + fForward = FALSE; + } + else if( dPos <= 0.0 ) + { + fTop = TRUE; + } + else + { + LPCDXKEY pKey; + double dStart, dStop, dFact = 0.0000000000001; + BOOL fOK = TRUE; + + if( pTag->UsrAscend ) + { + dStart = 0.0; + dStop = 1.0; + } + else + { + dStart = 1.0; + dStop = 0.0; + } + + pKey = pTag->UsrAscend ? pTag->topScopeKey : pTag->bottomScopeKey; + if( pKey ) + { + hb_cdxTagKeyFind( pTag, pKey ); + if( pTag->CurKey->rec == 0 || pTag->TagEOF || ! hb_cdxBottomScope( pTag ) ) + fOK = FALSE; + else + dStart = hb_cdxCountRelKeyPos( pTag->RootPage ); + } + pKey = pTag->UsrAscend ? pTag->bottomScopeKey : pTag->topScopeKey; + if( pKey && fOK ) + { + hb_cdxTagKeyFind( pTag, pKey ); + if( pTag->CurKey->rec == 0 || pTag->TagBOF || ! hb_cdxTopScope( pTag ) ) + fOK = FALSE; + else + dStop = hb_cdxCountRelKeyPos( pTag->RootPage ); + } + if( fOK ) + { + if( !pTag->UsrAscend ) + { + double dTmp = dStart; + dStart = dStop; + dStop = dTmp; + dPos = 1.0 - dPos; + } + if( dStart >= dStop - dFact ) + { + fTop = TRUE; + } + else + { + dPos = dPos * ( dStop - dStart ) + dStart; + pTag->fRePos = FALSE; + hb_cdxTagOpen( pTag ); + pTag->TagBOF = pTag->TagEOF = FALSE; + if( !hb_cdxGoToRelKeyPos( pTag->RootPage, dPos ) ) + { + fTop = TRUE; + } + else + { + hb_cdxSetCurKey( pTag->RootPage ); + if( !hb_cdxTopScope( pTag ) ) + fTop = TRUE; + else if( !hb_cdxBottomScope( pTag ) ) + fForward = FALSE; + } + } + } + } + if( !fOK ) + { + SELF_GOTO( ( AREAP ) pArea, 0 ); + } + else + { + if( fForward ) + { + if( fTop ) + hb_cdxTagGoTop( pTag ); + while( !pTag->TagEOF ) + { + if ( hb_cdxCheckRecordFilter( pArea, pTag->CurKey->rec ) ) + break; + hb_cdxTagSkipNext( pTag ); + } + if( pTag->TagEOF && !fTop ) + fForward = FALSE; + } + if( !fForward ) + { + hb_cdxTagGoBottom( pTag ); + while( !pTag->TagBOF ) + { + if ( hb_cdxCheckRecordFilter( pArea, pTag->CurKey->rec ) ) + break; + hb_cdxTagSkipPrev( pTag ); + } + if( pTag->TagBOF ) + { + pTag->CurKey->rec = 0; + } + } + SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec ); + } + hb_cdxIndexUnLockRead( pTag->pIndex ); + } +} + +/* + * DBOI_FINDREC find a specific record in the tag - it's useful for + * custom indexes when the same record can be stored more then once + * or when the used index key is unknown + */ +static BOOL hb_cdxDBOIFindRec( CDXAREAP pArea, LPCDXTAG pTag, ULONG ulRecNo, BOOL fCont ) +{ + BOOL fFound = FALSE; + + if ( pTag && ulRecNo ) + { + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + if ( fCont ) + { + if ( ! hb_cdxCurKeyRefresh( pArea, pTag ) ) + ulRecNo = 0; + else + hb_cdxTagSkipNext( pTag ); + } + else + { + hb_cdxTagGoTop( pTag ); + } + if ( ulRecNo ) + { + while ( !pTag->TagBOF && !pTag->TagEOF && hb_cdxBottomScope( pTag ) ) + { + if ( pTag->CurKey->rec == ulRecNo ) + { + fFound = TRUE; + break; + } + hb_cdxTagSkipNext( pTag ); + } + } + hb_cdxIndexUnLockRead( pTag->pIndex ); + } + SELF_GOTO( ( AREAP ) pArea, fFound ? ulRecNo : 0 ); + return fFound; +} + +static void hb_cdxClearLogPosInfo( CDXAREAP pArea ) +{ + LPCDXINDEX pIndex = pArea->lpIndexes; + LPCDXTAG pTag; + + while ( pIndex ) + { + pTag = pIndex->TagList; + while ( pTag ) + { + pTag->curKeyState &= ~( CDX_CURKEY_LOGPOS | CDX_CURKEY_LOGCNT ); + pTag = pTag->pNext; + } + pIndex = pIndex->pNext; + } +} + +/* + * -- BMDBFCDX 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, ("hb_cdxGoBottom(%p)", pArea)); + + if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + pTag = hb_cdxGetActiveTag( pArea ); + if ( ! pTag ) + return SUPER_GOBOTTOM( ( AREAP ) pArea ); + + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + + hb_cdxTagGoBottom( pTag ); + + pArea->fTop = FALSE; + pArea->fBottom = TRUE; + + retval = SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec ); + + if ( retval != FAILURE && pArea->fPositioned ) + { + retval = SELF_SKIPFILTER( ( AREAP ) pArea, -1 ); + + if ( pArea->fPositioned && CURKEY_LOGCNT( pTag ) ) + { + pTag->logKeyPos = pTag->logKeyCount; + CURKEY_SETLOGPOS( pTag ); + } + } + 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, ("hb_cdxGoTop(%p)", pArea)); + + if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + pTag = hb_cdxGetActiveTag( pArea ); + if ( ! pTag ) + return SUPER_GOTOP( ( AREAP ) pArea ); + + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + + hb_cdxTagGoTop( pTag ); + + pArea->fTop = TRUE; + pArea->fBottom = FALSE; + + retval = SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec ); + + if ( retval != FAILURE && pArea->fPositioned ) + retval = SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); + + if ( retval != FAILURE && pArea->fPositioned ) + { + pTag->logKeyPos = 1; + CURKEY_SETLOGPOS( pTag ); + } + + 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, ("hb_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, 0, EF_CANDEFAULT ); + return FAILURE; + } + else + { + LPCDXKEY pKey; + ERRCODE retval = SUCCESS; + BOOL fEOF = FALSE, fLast; + ULONG ulRec; + + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + pArea->fTop = pArea->fBottom = FALSE; + pArea->fEof = FALSE; + + if ( pTag->UsrUnique ) + fLast = !pTag->UsrAscend; + else + fLast = pTag->UsrAscend ? fFindLast : !fFindLast; + + /* TODO: runtime error if valtype(pKeyItm) != pTag->Type */ + pKey = hb_cdxKeyPutItem( NULL, pKeyItm, fLast ? CDX_MAX_REC_NUM : CDX_IGNORE_REC_NUM, pTag, TRUE, FALSE ); + + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + ulRec = hb_cdxTagKeyFind( pTag, pKey ); + if ( ( ulRec == 0 && ! fSoftSeek ) || pTag->TagEOF ) + fEOF = TRUE; + else /* if ( fSoftSeek ) */ + { + if ( ! hb_cdxBottomScope( pTag ) ) + fEOF = TRUE; + else if ( ! hb_cdxTopScope( pTag ) ) + { + hb_cdxTagGoTop( pTag ); + 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->fPositioned ) + { + retval = SELF_SKIPFILTER( ( AREAP ) pArea, fFindLast ? -1 : 1 ); + if ( retval != FAILURE && ulRec && pArea->fPositioned ) + { + 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 && + ( fEOF || ! hb_cdxTopScope( pTag ) || + ! hb_cdxBottomScope( pTag ) ) ) + { + retval = SELF_GOTO( ( AREAP ) pArea, 0 ); + } + pArea->fBof = FALSE; + hb_cdxKeyFree( pKey ); + return retval; + } +} + +#if ! defined( HB_SIXCDX ) + +static BYTE * hb_cdxPageGetKeyValActual( LPCDXPAGE pPage ) +{ + while ( pPage->Child ) + { + pPage = pPage->Child; + } + return hb_cdxPageGetKeyVal( pPage, pPage->iCurKey ); +} + + +/* + * compare two values using Tag conditions (len & type) + */ +static int hb_cdxValCompareWild( BYTE * val1, BYTE * val2, BOOL fExact ) +{ + return ( ( fExact ) ? hb_strMatchWildExact( (const char *) val2, (const char *) val1 ) : hb_strMatchWild( (const char *) val2, (const char *) val1 ) ) ? 0: 1; +} + +/* + * seek given Key in the Page or in its children + */ +static int hb_cdxPageSeekKeyWild( LPCDXPAGE pPage, LPCDXKEY pKey, ULONG ulKeyRec, BOOL fExact, BOOL fNext ) +{ + int k; + + k = ( ulKeyRec == CDX_MAX_REC_NUM ) ? -1 : 1; + + if ( fNext ? hb_cdxPageReadNextKey( pPage ) : hb_cdxPageReadTopKey( pPage ) ) + { + do + { + k = hb_cdxValCompareWild( pKey->val, hb_cdxPageGetKeyValActual( pPage ), fExact ); + } + while ( k && hb_cdxPageReadNextKey( pPage ) ); + + if ( k == 0 ) + { + while ( pPage->Child ) + { + pPage = pPage->Child; + } + if ( ulKeyRec == CDX_MAX_REC_NUM ) + k = 1; + else if ( ulKeyRec != CDX_IGNORE_REC_NUM ) + { + ULONG ulRec = hb_cdxPageGetKeyRec( pPage, pPage->iCurKey ); + if ( ulKeyRec > ulRec ) + k = 1; + else if ( ulKeyRec < ulRec ) + k = -1; + } + } + } + return k; +} + +/* + * find pKey in pTag return 0 or TagNO + */ +static ULONG hb_cdxTagKeyFindWild( LPCDXTAG pTag, LPCDXKEY pKey, BOOL fNext ) +{ + int K; + ULONG ulKeyRec = pKey->rec; + + pTag->fRePos = FALSE; + hb_cdxTagOpen( pTag ); + + pTag->TagBOF = pTag->TagEOF = FALSE; + K = hb_cdxPageSeekKeyWild( pTag->RootPage, pKey, ulKeyRec, FALSE, fNext ); + if ( ulKeyRec == CDX_MAX_REC_NUM ) + K = - K; + + if ( K > 0 ) + { + pTag->CurKey->rec = 0; + pTag->TagEOF = TRUE; + } + else + { + hb_cdxSetCurKey( pTag->RootPage ); + if ( K == 0 ) + return pTag->CurKey->rec; + } + return 0; +} + + +/* hb_cdxSeekWild */ +static ERRCODE hb_cdxSeekWild( CDXAREAP pArea, BOOL fSoftSeek, PHB_ITEM pKeyItm, BOOL fFindLast, BOOL fNext, BOOL bAll ) +{ + LPCDXTAG pTag; + + HB_TRACE(HB_TR_DEBUG, ("hb_cdxSeekWild(%p, %d, %p, %d, %d)", pArea, fSoftSeek, pKeyItm, fFindLast, fNext)); + + if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + pTag = hb_cdxGetActiveTag( pArea ); + + if ( ! pTag ) + { + hb_cdxErrorRT( pArea, EG_NOORDER, 1201, NULL, 0, EF_CANDEFAULT ); + return FAILURE; + } + else + { + LPCDXKEY pKey; + ERRCODE retval = SUCCESS; + BOOL fEOF = FALSE, fLast; + ULONG ulRec; + + if( ! bAll && pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + pArea->fTop = pArea->fBottom = FALSE; + pArea->fEof = FALSE; + + if ( pTag->UsrUnique ) + fLast = !pTag->UsrAscend; + else + fLast = pTag->UsrAscend ? fFindLast : !fFindLast; + + /* TODO: runtime error if valtype(pKeyItm) != pTag->Type */ + pKey = hb_cdxKeyPutItem( NULL, pKeyItm, fLast ? CDX_MAX_REC_NUM : CDX_IGNORE_REC_NUM, pTag, TRUE, FALSE ); + + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + ulRec = hb_cdxTagKeyFindWild( pTag, pKey, fNext ); + if ( ( ulRec == 0 && ! fSoftSeek ) || pTag->TagEOF ) + fEOF = TRUE; + else /* if ( fSoftSeek ) */ + { + if ( ! hb_cdxBottomScope( pTag ) ) + fEOF = TRUE; + else if ( ! hb_cdxTopScope( pTag ) ) + { + hb_cdxTagGoTop( pTag ); + 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->fPositioned ) + { + retval = SELF_SKIPFILTER( ( AREAP ) pArea, fFindLast ? -1 : 1 ); + if ( retval != FAILURE && ulRec && pArea->fPositioned ) + { + pArea->fFound = ( ulRec == pArea->ulRecNo || + hb_cdxValCompareWild( pKey->val, pTag->CurKey->val, FALSE ) == 0 ); + if ( ! pArea->fFound && ! fSoftSeek ) + fEOF = TRUE; + } + } + } + if ( retval != FAILURE && + ( fEOF || ! hb_cdxTopScope( pTag ) || + ! hb_cdxBottomScope( pTag ) ) ) + { + retval = SELF_GOTO( ( AREAP ) pArea, 0 ); + } + pArea->fBof = FALSE; + hb_cdxKeyFree( pKey ); + return retval; + } +} + +HB_FUNC( BM_TURBO ) +{ + bTurbo = ISLOG( 1 ) ? hb_parl( 1 ) : FALSE; + hb_retl( bTurbo ); +} + +HB_FUNC( BM_DBGETFILTERARRAY ) +{ + CDXAREAP pArea = (CDXAREAP) hb_rddGetCurrentWorkAreaPointer(); + PHB_ITEM pList = hb_itemArrayNew( 0 ); + ULONG ulRec,ulRecOld; + + if ( pArea->dbfi.fOptimized ) + { + ULONG ulSize = ( ( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size+1) >> 5 ) + 1; + ULONG ulLong, ulByte, ulBytes, ulRecno; + + ulRecOld = pArea->ulRecNo; + + for ( ulLong = 0; ulLong < ulSize; ulLong++ ) + if ( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap[ulLong] ) + for ( ulByte = (ulLong<<2), ulBytes = 0; ulBytes < 4; ulByte++, ulBytes++ ) + if ( ((char*)( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap)[ulByte] ) + for ( ulRec=(ulByte<<3)+1, ulRecno=0; ulRecno < 8; ulRec++, ulRecno++ ) + if ( hb_cdxCheckRecordFilter( pArea, ulRec ) ) + hb_arrayAdd( pList, hb_itemPutNL( NULL, ulRec ) ); + + SELF_GOTO( (AREAP) pArea, ulRecOld ); + } + hb_itemRelease( hb_itemReturnForward( pList ) ); +} + +HB_FUNC( BM_DBSETFILTERARRAY ) +{ + AREAP pArea = (AREAP) hb_rddGetCurrentWorkAreaPointer(); + PHB_ITEM pArray = hb_param( 1, HB_IT_ARRAY ); + ULONG ulPos,ulRecCount; + + if( pArea ) + { + if( pArray ) + { + LPCDXTAG pTag; + /* Limpiamos el filtro activo */ + if( SELF_CLEARFILTER( pArea ) != SUCCESS ) + return; + + pArea->dbfi.itmCobExpr = hb_itemPutC( NULL, "" ); + pArea->dbfi.abFilterText = hb_itemPutC( NULL, "" ); + pArea->dbfi.fOptimized = TRUE; + pArea->dbfi.fFilter = TRUE; + + SELF_RECCOUNT( ( AREAP ) pArea, &ulRecCount ); + pArea->dbfi.lpvCargo = hb_xgrab( sizeof( BM_FILTER ) ); + memset( pArea->dbfi.lpvCargo, 0, sizeof( BM_FILTER ) ); + + ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size = ulRecCount; + ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap = (ULONG *) hb_xgrab( sizeof(ULONG) * (((ulRecCount+1) >> 5) + 1) ); + for ( ulPos = 1; ulPos <= ulRecCount; ulPos++ ) + BM_ClrBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ulRecCount, ulPos ); + for ( ulPos = 1; ulPos <= hb_arrayLen( pArray ); ulPos++ ) + BM_SetBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ulRecCount, (ULONG) hb_arrayGetNL( pArray, ulPos ) ); + pTag = hb_cdxGetActiveTag( (CDXAREAP) pArea ); + if ( pTag ) // Con índice activo + CURKEY_SETLOGCNT( pTag, (hb_arrayLen( pArray )) ) + } + else + hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, "BM_DBSETFILTERARRAY" ); + } + else + hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "BM_DBSETFILTERARRAY" ); +} + +HB_FUNC( BM_DBSETFILTERARRAYADD ) +{ + AREAP pArea = (AREAP) hb_rddGetCurrentWorkAreaPointer(); + PHB_ITEM pArray = hb_param( 1, HB_IT_ARRAY ); + ULONG ulPos,ulAdd = 0; + + if( pArea && pArea->dbfi.fOptimized ) + { + if( pArray ) + { + LPCDXTAG pTag; + + for ( ulPos = 1; ulPos <= hb_arrayLen( pArray ); ulPos++ ) + if ( ! BM_GetBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, (ULONG) hb_arrayGetNL( pArray, ulPos ) ) ) + { + BM_SetBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, (ULONG) hb_arrayGetNL( pArray, ulPos ) ); + ulAdd++; + } + pTag = hb_cdxGetActiveTag( (CDXAREAP) pArea ); + if ( pTag ) // Con índice activo + CURKEY_SETLOGCNT( pTag, (pTag->logKeyCount + ulAdd) ) + } + else + hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, "BM_DBSETFILTERARRAYADD" ); + } + else + hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "BM_DBSETFILTERARRAYADD" ); +} + +HB_FUNC( BM_DBSETFILTERARRAYDEL ) +{ + AREAP pArea = (AREAP) hb_rddGetCurrentWorkAreaPointer(); + PHB_ITEM pArray = hb_param( 1, HB_IT_ARRAY ); + ULONG ulPos,ulDel = 0; + + if( pArea && pArea->dbfi.fOptimized ) + { + if( pArray ) + { + LPCDXTAG pTag; + + for ( ulPos = 1; ulPos <= hb_arrayLen( pArray ); ulPos++ ) + if ( BM_GetBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, (ULONG) hb_arrayGetNL( pArray, ulPos ) ) ) + { + BM_ClrBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, (ULONG) hb_arrayGetNL( pArray, ulPos ) ); + ulDel++; + } + pTag = hb_cdxGetActiveTag( (CDXAREAP) pArea ); + if ( pTag ) // Con índice activo + CURKEY_SETLOGCNT( pTag, pTag->logKeyCount - ulDel ) + } + else + hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, "BM_DBSETFILTERARRAYDEL" ); + } + else + hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "BM_DBSETFILTERARRAYDEL" ); +} + + +HB_FUNC( BM_DBSEEKWILD ) +{ + PHB_ITEM pKey; + BOOL bAll, bNext, bSoftSeek, bFindLast, fFound; + AREAP pArea = (AREAP) hb_rddGetCurrentWorkAreaPointer(); + + if( pArea ) + { + if( !ISNIL( 1 ) ) + { + pKey = hb_param( 1, HB_IT_ANY ); + bSoftSeek = ISLOG( 2 ) ? hb_parl( 2 ) : hb_set.HB_SET_SOFTSEEK; + bFindLast = ISLOG( 3 ) ? hb_parl( 3 ) : FALSE; + bNext = ISLOG( 4 ) ? hb_parl( 4 ) : FALSE; + bAll = ISLOG( 5 ) ? hb_parl( 5 ) : FALSE; + if ( bAll) + { + PHB_ITEM pList; + pList = hb_itemNew( NULL ); + hb_arrayNew( pList, 0 ); + SELF_GOTOP( ( AREAP ) pArea ); + if ( hb_cdxSeekWild( (CDXAREAP) pArea, bSoftSeek, pKey, bFindLast, FALSE, bAll ) == SUCCESS && + pArea->fEof == FALSE && + SELF_FOUND( pArea, &fFound ) == SUCCESS ) + { + hb_arrayAdd( pList, hb_itemPutNL( NULL, ((CDXAREAP) pArea)->ulRecNo ) ); + while ( hb_cdxSeekWild( (CDXAREAP) pArea, bSoftSeek, pKey, bFindLast, TRUE, bAll ) == SUCCESS && + pArea->fEof == FALSE && + SELF_FOUND( pArea, &fFound ) == SUCCESS ) + { + hb_arrayAdd( pList, hb_itemPutNL( NULL, ((CDXAREAP) pArea)->ulRecNo ) ); + } + } + hb_itemReturn( pList ); + hb_itemRelease( pList ); + return; + } + else + if( hb_cdxSeekWild( (CDXAREAP) pArea, bSoftSeek, pKey, bFindLast, bNext, bAll ) == SUCCESS ) + { + if( SELF_FOUND( pArea, &fFound ) == SUCCESS ) + { + hb_retl( fFound ); + return; + } + } + } + else + hb_errRT_DBCMD( EG_ARG, EDBCMD_SEEK_BADPARAMETER, NULL, "BM_DBSEEKWILD" ); + } + else + hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "BM_DBSEEKWILD" ); + + hb_retl( FALSE ); + +} + +#endif + +/* ( DBENTRYP_L ) hb_cdxSkip : NULL */ +static ERRCODE hb_cdxSkip( CDXAREAP pArea, LONG lToSkip ) +{ + LPCDXTAG pTag; + ULONG ulPos, ulRec; + + HB_TRACE(HB_TR_DEBUG, ("hb_cdxSkip(%p, %ld)", pArea, lToSkip)); + + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + pTag = lToSkip == 0 ? NULL : hb_cdxGetActiveTag( pArea ); + if( pTag && pArea->fPositioned && CURKEY_LOGPOS( pTag ) ) + { + ulPos = pTag->logKeyPos; + ulRec = pTag->logKeyRec; + } + else + { + ulPos = ulRec = 0; + } + + if ( SUPER_SKIP( ( AREAP ) pArea, lToSkip ) == FAILURE ) + return FAILURE; + + if ( pTag ) + { + if ( ulPos && ( pTag->logKeyPos != ulPos || pTag->logKeyRec != ulRec || + ( pTag->curKeyState & CDX_CURKEY_LOGPOS ) == 0 ) ) + { + ulPos = 0; + } + + if ( lToSkip > 0 ) + { + if ( pArea->fEof ) + { + if ( lToSkip == 1 && ulPos && !CURKEY_LOGCNT( pTag ) ) + CURKEY_SETLOGCNT( pTag, ulPos ) + } + else if ( ulPos ) + { + pTag->logKeyPos += lToSkip - ( ulPos ? 0 : 1 ); + pTag->logKeyRec = pArea->ulRecNo; + } + } + else if ( pArea->fBof ) + { + if ( pArea->fPositioned ) + { + pTag->logKeyPos = 1; + CURKEY_SETLOGPOS( pTag ); + } + } + else if ( ulPos ) + { + pTag->logKeyPos += lToSkip + ( ulPos ? 0 : 1 ); + pTag->logKeyRec = pArea->ulRecNo; + } + } + return SUCCESS; +} + +/* ( DBENTRYP_L ) hb_cdxSkipFilter */ +/* + * Reposition cursor respecting any filter setting. + */ +ERRCODE hb_cdxSkipFilter( CDXAREAP pArea, LONG lUpDown ) +{ + BOOL fBottom, fDeleted; + ERRCODE uiError; + + HB_TRACE(HB_TR_DEBUG, ("hb_cdxSkipFilter(%p, %ld)", pArea, lUpDown)); + + if( !hb_set.HB_SET_DELETED && pArea->dbfi.itmCobExpr == NULL ) + return SUCCESS; + + /* Since lToSkip is passed to SkipRaw, it should never request more than + a single skip. + The implied purpose of hb_cdxSkipFilter is to get off of a "bad" record + after a skip was performed, NOT to skip lToSkip filtered records. + */ + lUpDown = ( lUpDown < 0 ? -1 : 1 ); + + /* remember if we are here after SELF_GOTOP() */ + fBottom = pArea->fBottom; + + while( !pArea->fBof && !pArea->fEof ) + { + /* SET DELETED */ + if( hb_set.HB_SET_DELETED ) + { + if( SELF_DELETED( (AREAP) pArea, &fDeleted ) != SUCCESS ) + return FAILURE; + if( fDeleted ) + { + if( SELF_SKIPRAW( (AREAP) pArea, lUpDown ) != SUCCESS ) + return FAILURE; + continue; + } + } + + /* SET FILTER TO */ + if( pArea->dbfi.fFilter ) + { + if( ! hb_cdxCheckRecordFilter( pArea, pArea->ulRecNo ) ) + { + if( SELF_SKIPRAW( (AREAP) pArea, lUpDown ) != SUCCESS ) + return FAILURE; + continue; + } + } + + break; + } + + /* + * The only one situation when we should repos is backward skipping + * if we are at BOTTOM position (it's SKIPFILTER called from GOBOTTOM) + * then GOEOF() if not then GOTOP() + */ + if( pArea->fBof && lUpDown < 0 ) + { + if( fBottom ) + { + /* GOTO EOF (phantom) record - + this is the only one place where GOTO is used by xHarbour + directly and RDD which does not operate on numbers should + serve this method only as SELF_GOEOF() synonym. If it's a + problem then we can remove this if and always use SELF_GOTOP() + but it also means second table scan if all records filtered + are out of filter so I do not want to do that. I will prefer + explicit add SELF_GOEOF() method + */ + uiError = SELF_GOTO( (AREAP) pArea, 0 ); + } + else + { + uiError = SELF_GOTOP( (AREAP) pArea ); + pArea->fBof = TRUE; + } + } + else + { + uiError = SUCCESS; + } + + return uiError; +} + +/* ( DBENTRYP_L ) hb_cdxSkipRaw */ +static ERRCODE hb_cdxSkipRaw( CDXAREAP pArea, LONG lToSkip ) +{ + LPCDXTAG pTag; + ERRCODE retval; + BOOL fOut = FALSE, fForward; + + HB_TRACE(HB_TR_DEBUG, ("hb_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 ); + + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + fForward = ( lToSkip > 0 ); + + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + if ( ! hb_cdxCurKeyRefresh( pArea, pTag ) ) + { + if ( fForward ) + { + if ( pTag->TagEOF || !hb_cdxBottomScope( pTag ) ) + fOut = TRUE; + else if ( pTag->UsrAscend && hb_cdxTopScope( pTag ) ) + lToSkip--; + } + else if ( pArea->fPositioned ) + { + if ( pTag->TagEOF || !hb_cdxTopScope( pTag ) ) + fOut = TRUE; + else if ( !pTag->UsrAscend && hb_cdxBottomScope( pTag ) ) + lToSkip++; + } + } + if ( fForward ) + { + if ( !fOut ) + { + while ( lToSkip-- > 0 ) + { + hb_cdxTagSkipNext( pTag ); + if ( pTag->TagEOF ) + { + fOut = TRUE; + break; + } + } + } + retval = SELF_GOTO( ( AREAP ) pArea, ( pTag->TagEOF || fOut ) + ? 0 : pTag->CurKey->rec ); + } + else /* if ( lToSkip < 0 ) */ + { + if ( fOut ) + hb_cdxTagGoTop( pTag ); + else + { + while ( lToSkip++ < 0 ) + { + hb_cdxTagSkipPrev( pTag ); + if ( pTag->TagBOF ) + { + fOut = TRUE; + break; + } + } + } + retval = SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec ); + pArea->fBof = fOut; + } + hb_cdxIndexUnLockRead( pTag->pIndex ); + /* Update Bof and Eof flags */ + /* + if( fForward ) + pArea->fBof = FALSE; + else + pArea->fEof = FALSE; + */ + return retval; +} + +/* ( DBENTRYP_VF ) hb_cdxAddField : NULL */ +/* ( DBENTRYP_B ) hb_cdxAppend */ +static ERRCODE hb_cdxAppend( CDXAREAP pArea, BOOL bUnLockAll ) +{ + if ( SUPER_APPEND( (AREAP) pArea, bUnLockAll ) == SUCCESS ) + { + if ( pArea->dbfi.fFilter && pArea->dbfi.fOptimized ) + { + ULONG ulRecCount, bytes; + + SELF_RECCOUNT( ( AREAP ) pArea, &ulRecCount ); + bytes = ( (ulRecCount + 1) >> 5 ) + 1; + + if ( ( (ulRecCount) >> 5 ) + 1 < bytes ) + { + ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap = (ULONG *) hb_xrealloc( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, bytes << 2 ); + ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size = ulRecCount; + } + pArea->dbfi.fFilter = FALSE; + if ( hb_cdxCheckRecordFilter( pArea, ulRecCount ) ) + { + LPCDXTAG pTag; + BM_SetBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, ulRecCount ); + pTag = hb_cdxGetActiveTag( (CDXAREAP) pArea ); + if ( pTag && CURKEY_LOGCNT(pTag) ) // Con índice activo + CURKEY_SETLOGCNT( pTag, (pTag)->logKeyCount + 1 ) + } + else + BM_ClrBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, ulRecCount ); + pArea->dbfi.fFilter = TRUE; + } + return SUCCESS; + } + else + return FAILURE; +} +/* ( DBENTRYP_I ) hb_cdxCreateFields : NULL */ +/* ( DBENTRYP_V ) hb_cdxDeleteRec */ +static ERRCODE hb_cdxDeleteRec( CDXAREAP pArea ) +{ + if ( SUPER_DELETE( (AREAP) pArea ) == SUCCESS ) + { + if ( pArea->dbfi.fFilter && pArea->dbfi.fOptimized ) + { + pArea->dbfi.fFilter = FALSE; + if ( hb_cdxCheckRecordFilter( pArea, pArea->ulRecNo ) ) + { + if ( ! BM_GetBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, pArea->ulRecNo ) ) + { + LPCDXTAG pTag; + BM_SetBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, pArea->ulRecNo ); + pTag = hb_cdxGetActiveTag( (CDXAREAP) pArea ); + if ( pTag && CURKEY_LOGCNT(pTag) ) + CURKEY_SETLOGCNT( pTag, (pTag)->logKeyCount + 1 ) + } + } + else + { + if ( BM_GetBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, pArea->ulRecNo ) ) + { + LPCDXTAG pTag; + BM_ClrBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, pArea->ulRecNo ); + pTag = hb_cdxGetActiveTag( (CDXAREAP) pArea ); + if ( pTag && CURKEY_LOGCNT(pTag) ) + CURKEY_SETLOGCNT( pTag, (pTag)->logKeyCount - 1 ) + } + } + pArea->dbfi.fFilter = TRUE; + } + return SUCCESS; + } + else + return FAILURE; +} + +/* ( 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; + + HB_TRACE(HB_TR_DEBUG, ("hb_cdxFlush(%p)", pArea)); + + if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + uiError = SUPER_FLUSH( ( AREAP ) pArea ); + + if ( hb_set.HB_SET_HARDCOMMIT ) + { + pIndex = pArea->lpIndexes; + while ( pIndex ) + { + if ( pIndex->hFile != FS_ERROR && pIndex->fFlush ) + { + hb_fsCommit( pIndex->hFile ); + pIndex->fFlush = FALSE; + } + 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; + LPDBRELINFO lpdbPendingRel; + + 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; + } + } + + /* The pending relation may move the record pointer so we should + disable them for KEY/FOR evaluation */ + lpdbPendingRel = pArea->lpdbPendingRel; + pArea->lpdbPendingRel = NULL; + + /* 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 ); + + 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_cdxTagKeyDel( pTag, pTag->HotKey ); + 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 ); + + /* Restore disabled pending relation */ + pArea->lpdbPendingRel = lpdbPendingRel; + } + + 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 ); + 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 */ +static ERRCODE hb_cdxPutRec( CDXAREAP pArea, BYTE * pBuffer ) +{ + if ( SUPER_PUTREC( (AREAP) pArea, pBuffer ) == SUCCESS ) + { + if ( pArea->dbfi.fFilter && pArea->dbfi.fOptimized ) + { + pArea->dbfi.fFilter = FALSE; + + if ( hb_cdxCheckRecordFilter( pArea, pArea->ulRecNo ) ) + { + if ( ! BM_GetBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, pArea->ulRecNo ) ) + { + LPCDXTAG pTag; + BM_SetBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, pArea->ulRecNo ); + pTag = hb_cdxGetActiveTag( pArea ); + if ( pTag ) + CURKEY_SETLOGCNT( pTag, pTag->logKeyCount + 1 ) + } + } + else + { + if ( BM_GetBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, pArea->ulRecNo ) ) + { + LPCDXTAG pTag; + BM_ClrBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, pArea->ulRecNo ); + pTag = hb_cdxGetActiveTag( pArea ); + if ( pTag ) + CURKEY_SETLOGCNT( pTag, pTag->logKeyCount - 1 ) + } + } + pArea->dbfi.fFilter = TRUE; + } + return SUCCESS; + } + else + return FAILURE; +} +/* ( DBENTRYP_SI ) hb_cdxPutValue : NULL */ +/* ( DBENTRYP_V ) hb_cdxRecall */ +static ERRCODE hb_cdxRecall( CDXAREAP pArea ) +{ + if ( SUPER_RECALL( (AREAP) pArea ) == SUCCESS ) + { + if ( pArea->dbfi.fFilter && pArea->dbfi.fOptimized ) + { + pArea->dbfi.fFilter = FALSE; + if ( hb_cdxCheckRecordFilter( pArea, pArea->ulRecNo ) ) + BM_SetBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, pArea->ulRecNo ); + else + BM_ClrBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size, pArea->ulRecNo ); + pArea->dbfi.fFilter = TRUE; + } + return SUCCESS; + } + else + return FAILURE; +} + +/* ( DBENTRYP_ULP ) hb_cdxRecCount : NULL */ +/* ( DBENTRYP_ISI ) hb_cdxRecInfo : NULL */ +/* ( DBENTRYP_ULP ) hb_cdxRecNo : NULL */ +/* ( DBENTRYP_I ) hb_cdxRecId : 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 ) +{ + ERRCODE errCode; + + HB_TRACE(HB_TR_DEBUG, ("hb_cdxClose(%p)", pArea)); + + if ( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + errCode = SUPER_CLOSE( ( AREAP ) pArea ); + + if( errCode == SUCCESS ) + { + if ( pArea->pSort ) + { + hb_cdxSortFree( pArea->pSort ); + pArea->pSort = NULL; + } + + 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" + "cdxTimeIdxBld=%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) cdxTimeIdxBld / 1000000, + (double) ( cdxTimeIntBld + cdxTimeExtBld + cdxTimeIdxBld + + 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 errCode; +} + +/* ( 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 ) +{ + ERRCODE errCode = SUCCESS; + + HB_TRACE(HB_TR_DEBUG, ("hb_cdxOpen(%p, %p)", pArea, pOpenInfo)); + + if ( !pArea->bLockType ) + { + PHB_ITEM pItem = hb_itemNew( NULL ); + if( SELF_INFO( ( AREAP ) pArea, DBI_LOCKSCHEME, pItem ) != SUCCESS ) + { + hb_itemRelease( pItem ); + return FAILURE; + } + pArea->bLockType = hb_itemGetNI( pItem ); + hb_itemRelease( pItem ); + if( pArea->bLockType == 0 ) + { + pArea->bLockType = DB_DBFLOCK_VFP; + } + } + if ( SUPER_OPEN( ( AREAP ) pArea, pOpenInfo ) == FAILURE ) + { + return FAILURE; + } + + /* If SET_AUTOPEN open index */ +#ifdef HB_CDX_CLIP_AUTOPEN + if ( hb_set.HB_SET_AUTOPEN ) +#else + if ( pArea->fHasTags && hb_set.HB_SET_AUTOPEN ) +#endif + { + char szFileName[ _POSIX_PATH_MAX + 1 ]; + + pArea->fHasTags = FALSE; + hb_cdxCreateFName( pArea, NULL, NULL, szFileName, NULL ); + if ( hb_spFile( ( BYTE * ) szFileName, NULL ) ) + { + DBORDERINFO pOrderInfo; + + pOrderInfo.itmResult = hb_itemPutNI( NULL, 0 ); + pOrderInfo.atomBagName = hb_itemPutC( NULL, szFileName ); + pOrderInfo.itmNewVal = NULL; + pOrderInfo.itmOrder = NULL; + errCode = SELF_ORDLSTADD( ( AREAP ) pArea, &pOrderInfo ); + if( errCode == SUCCESS ) + { + pOrderInfo.itmOrder = hb_itemPutNI( NULL, hb_set.HB_SET_AUTORDER ); + errCode = SELF_ORDLSTFOCUS( ( AREAP ) pArea, &pOrderInfo ); + hb_itemRelease( pOrderInfo.itmOrder ); + if( errCode == SUCCESS ) + errCode = SELF_GOTOP( ( AREAP ) pArea ); + } + hb_itemRelease( pOrderInfo.atomBagName ); + hb_itemRelease( pOrderInfo.itmResult ); + } + } + else + { + pArea->fHasTags = FALSE; + } + + return errCode; +} + +/* ( 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 : NULL */ + +/* ( DBENTRYP_VEI ) hb_cdxEval : NULL */ + +/* ( DBENTRYP_V ) hb_cdxPack */ +static ERRCODE hb_cdxPack( CDXAREAP pArea ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_cdxPack(%p)", pArea )); + + if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + if ( SUPER_PACK( ( AREAP ) pArea ) == SUCCESS ) + { + return SELF_ORDLSTREBUILD( ( AREAP ) 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; + + if ( SUPER_ZAP( ( AREAP ) pArea ) == SUCCESS ) + { + return SELF_ORDLSTREBUILD( ( AREAP ) 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[ CDX_MAXTAGNAMELEN + 1 ]; + char szFileName[ _POSIX_PATH_MAX + 1 ]; + LPCDXINDEX pIndex, * pIndexPtr; + BOOL fProd, bRetry; + + HB_TRACE(HB_TR_DEBUG, ("hb_cdxOrderListAdd(%p, %p)", pArea, pOrderInfo)); + + if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + if ( hb_itemGetCLen( pOrderInfo->atomBagName ) == 0 ) + return FAILURE; + + hb_cdxCreateFName( pArea, hb_itemGetCPtr( pOrderInfo->atomBagName ), + &fProd, szFileName, szBaseName ); + +/* + if ( ! szBaseName[0] ) + return FAILURE; +*/ + pIndex = hb_cdxFindBag( pArea, szFileName ); + + if ( pIndex ) + { + /* index already open, do nothing */ + if ( ! pArea->uiTag ) + { + pArea->uiTag = hb_cdxGetTagNumber( pArea, pIndex->TagList ); + SELF_GOTOP( ( AREAP ) pArea ); + } + return SUCCESS; + } + + uiFlags = ( pArea->fReadonly ? FO_READ : FO_READWRITE ) | + ( pArea->fShared ? FO_DENYNONE : FO_EXCLUSIVE ); + do + { + hFile = hb_fsExtOpen( ( BYTE * ) szFileName, NULL, uiFlags | + FXO_DEFAULTS | FXO_SHARELOCK | FXO_COPYNAME, + NULL, NULL ); + if( hFile == FS_ERROR ) + bRetry = ( hb_cdxErrorRT( pArea, EG_OPEN, EDBF_OPEN_INDEX, szFileName, + hb_fsError(), EF_CANRETRY | EF_CANDEFAULT ) == E_RETRY ); + else + { + if( hb_fsSeekLarge( hFile, 0, FS_END ) <= ( HB_FOFFSET ) sizeof( CDXTAGHEADER ) ) + { + hb_fsClose( hFile ); + hFile = FS_ERROR; + hb_cdxErrorRT( pArea, EG_CORRUPTION, EDBF_CORRUPT, + szFileName, hb_fsError(), EF_CANDEFAULT ); + } + bRetry = FALSE; + } + + } while ( bRetry ); + + if ( hFile == FS_ERROR ) + { + return FAILURE; + } + + pIndex = hb_cdxIndexNew( pArea ); + pIndex->hFile = hFile; + pIndex->fShared = pArea->fShared; + pIndex->fReadonly = pArea->fReadonly; + pIndex->szFileName = hb_strdup( szFileName ); + + pIndexPtr = &pArea->lpIndexes; + while ( *pIndexPtr != NULL ) + pIndexPtr = &( *pIndexPtr )->pNext; + *pIndexPtr = pIndex; + + if ( ! hb_cdxIndexLoad( pIndex, szBaseName ) ) + { + /* index file is corrupted */ + *pIndexPtr = NULL; + hb_cdxIndexFree( pIndex ); + hb_cdxErrorRT( pArea, EG_CORRUPTION, EDBF_CORRUPT, + szFileName, hb_fsError(), EF_CANDEFAULT ); + return FAILURE; + } + + if( fProd ) + pArea->fHasTags = TRUE; + + /* bmdbfcdx specific: If there was no controlling order, set this one. + * This is the behaviour of Clipper's bmdbfcdx, 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, ("hb_cdxOrderListClear(%p)", pArea)); + + if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + +#ifdef HB_CDX_CLIP_AUTOPEN + hb_cdxOrdListClear( pArea, !hb_set.HB_SET_AUTOPEN, NULL ); +#else + hb_cdxOrdListClear( pArea, !pArea->fHasTags || !hb_set.HB_SET_AUTOPEN, NULL ); +#endif + pArea->uiTag = 0; + + return SUCCESS; +} + +/* TODO: in the future, now there is no API call to SELF_ORDLSTDELETE */ +/* ( DBENTRYP_OI ) hb_cdxOrderListDelete : NULL */ + +/* ( DBENTRYP_OI ) hb_cdxOrderListFocus */ +static ERRCODE hb_cdxOrderListFocus( CDXAREAP pArea, LPDBORDERINFO pOrderInfo ) +{ + LPCDXTAG pTag; + + HB_TRACE(HB_TR_DEBUG, ("hb_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 ) + { + hb_cdxFindTag( pArea, pOrderInfo->itmOrder, pOrderInfo->atomBagName, &(pArea->uiTag) ); + /* 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, ("hb_cdxPack(%p)", pArea )); + + if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + if ( pArea->fShared ) + { + hb_cdxErrorRT( pArea, EG_SHARED, EDBF_SHARED, pArea->szDataFileName, 0, 0 ); + return FAILURE; + } + if ( pArea->fReadonly ) + { + hb_cdxErrorRT( pArea, EG_READONLY, EDBF_READONLY, pArea->szDataFileName, 0, 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, fProd, fAscend = TRUE, fCustom = FALSE, + fTemporary = FALSE, fExclusive = FALSE; + PHB_ITEM pKeyExp, pForExp = NULL, pResult; + char szCpndTagName[ CDX_MAXTAGNAMELEN + 1 ], szTagName[ CDX_MAXTAGNAMELEN + 1 ]; + char szFileName[ _POSIX_PATH_MAX + 1 ], szTempFile[ _POSIX_PATH_MAX + 1 ]; + char *szFor = NULL; + LPCDXINDEX pIndex; + LPCDXTAG pTag; + USHORT uiLen; + BYTE bType; + + HB_TRACE(HB_TR_DEBUG, ("hb_cdxOrderCreate(%p, %p)", pArea, pOrderInfo)); + + if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + /* 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 * ) hb_itemGetCPtr( pOrderInfo->abExpr ) ) == 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 ( SELF_EVALBLOCK( ( AREAP ) pArea, pKeyExp ) == FAILURE ) + { + hb_vmDestroyBlockOrMacro( pKeyExp ); + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + return FAILURE; + } + pResult = pArea->valResult; + pArea->valResult = NULL; + + bType = hb_cdxItemType( pResult ); + switch ( bType ) + { + case 'N': + case 'D': + uiLen = 8; + break; + case 'L': + uiLen = 1; + break; + case 'C': + uiLen = HB_CDXMAXKEY( hb_itemGetCLen( pResult ) ); + break; + default: + bType = 'U'; + uiLen = 0; + } + hb_itemRelease( pResult ); + + if ( bType == 'U' || uiLen == 0 ) + { + hb_vmDestroyBlockOrMacro( pKeyExp ); + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + hb_cdxErrorRT( pArea, bType == 'U' ? EG_DATATYPE : EG_DATAWIDTH, + 1026, NULL, 0, 0 ); + return FAILURE; + } + if ( pArea->lpdbOrdCondInfo ) + { + fAscend = !pArea->lpdbOrdCondInfo->fDescending; + fCustom = pArea->lpdbOrdCondInfo->fCustom; + fTemporary = pArea->lpdbOrdCondInfo->fTemporary; + fExclusive = pArea->lpdbOrdCondInfo->fExclusive; + + /* Check conditional expression */ + szFor = ( char * ) pArea->lpdbOrdCondInfo->abFor; + if ( pArea->lpdbOrdCondInfo->itmCobFor ) + /* If we have a codeblock for the conditional expression, use it */ + pForExp = hb_itemNew( pArea->lpdbOrdCondInfo->itmCobFor ); + else if ( pArea->lpdbOrdCondInfo->abFor ) + { + /* Otherwise, try compiling the conditional expression string */ + if ( SELF_COMPILE( (AREAP) pArea, pArea->lpdbOrdCondInfo->abFor ) == FAILURE ) + { + hb_vmDestroyBlockOrMacro( pKeyExp ); + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + return FAILURE; + } + pForExp = pArea->valResult; + pArea->valResult = NULL; + } + } + /* Test conditional expression */ + if ( pForExp ) + { + BOOL fOK; + + if ( SELF_EVALBLOCK( ( AREAP ) pArea, pForExp ) == FAILURE ) + { + hb_vmDestroyBlockOrMacro( pKeyExp ); + hb_vmDestroyBlockOrMacro( pForExp ); + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + return FAILURE; + } + fOK = hb_itemType( pArea->valResult ) == HB_IT_LOGICAL; + hb_itemRelease( pArea->valResult ); + pArea->valResult = NULL; + if ( ! fOK ) + { + hb_vmDestroyBlockOrMacro( pKeyExp ); + hb_vmDestroyBlockOrMacro( pForExp ); + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + hb_cdxErrorRT( pArea, EG_DATATYPE, EDBF_INVALIDFOR, NULL, 0, 0 ); + return FAILURE; + } + } + + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + + /* + * abBagName -> cBag, atomBagName -> cTag + * The following scheme implemented: + * 1. abBagName == NULL -> add the Tag to the structural index + * 2. atomBagName == NULL -> overwrite any index file of abBagName + * 3. ads the Tag to index file + */ + + hb_cdxCreateFName( pArea, ( char * ) pOrderInfo->abBagName, + &fProd, szFileName, szCpndTagName ); + + if ( pOrderInfo->atomBagName && pOrderInfo->atomBagName[0] ) + { + hb_strncpyUpperTrim( szTagName, ( char * ) pOrderInfo->atomBagName, CDX_MAXTAGNAMELEN ); + fNewFile = FALSE; + } + else + { + hb_strncpy( szTagName, szCpndTagName, CDX_MAXTAGNAMELEN ); + fNewFile = TRUE; + } + + if ( !pArea->lpdbOrdCondInfo || + ( pArea->lpdbOrdCondInfo->fAll && !pArea->lpdbOrdCondInfo->fAdditive ) ) +#ifdef HB_CDX_CLIP_AUTOPEN + hb_cdxOrdListClear( pArea, !hb_set.HB_SET_AUTOPEN, NULL ); +#else + hb_cdxOrdListClear( pArea, !pArea->fHasTags || !hb_set.HB_SET_AUTOPEN, NULL ); +#endif + + pIndex = hb_cdxFindBag( pArea, szFileName ); + + if ( fNewFile && pIndex != NULL ) + { + LPCDXINDEX * pIndexPtr = &pArea->lpIndexes; + while ( *pIndexPtr ) + { + if ( pIndex == *pIndexPtr ) + { + *pIndexPtr = pIndex->pNext; + break; + } + pIndexPtr = &(*pIndexPtr)->pNext; + } + hb_cdxIndexFree( pIndex ); + pIndex = NULL; + } + fOpenedIndex = ( pIndex != NULL ); + + if ( !fOpenedIndex ) + { + FHANDLE hFile; + BOOL bRetry, fShared = pArea->fShared && !fTemporary && !fExclusive; + + do + { + if( fTemporary ) + { + hFile = hb_fsCreateTemp( NULL, NULL, FC_NORMAL, ( BYTE * ) szTempFile ); + fNewFile = TRUE; + } + else + { + hFile = hb_fsExtOpen( ( BYTE * ) szFileName, NULL, FO_READWRITE | + ( fShared ? FO_DENYNONE : FO_EXCLUSIVE ) | + ( fNewFile ? FXO_TRUNCATE : FXO_APPEND ) | + FXO_DEFAULTS | FXO_SHARELOCK | FXO_COPYNAME, + NULL, NULL ); + } + if( hFile == FS_ERROR ) + bRetry = ( hb_cdxErrorRT( pArea, EG_CREATE, EDBF_CREATE, szFileName, + hb_fsError(), EF_CANRETRY | EF_CANDEFAULT ) == E_RETRY ); + else + { + bRetry = FALSE; + if ( !fNewFile ) + fNewFile = ( hb_fsSeekLarge( hFile, 0, FS_END ) == 0 ); + } + + } while ( bRetry ); + + if ( hFile != FS_ERROR ) + { + pIndex = hb_cdxIndexNew( pArea ); + pIndex->hFile = hFile; + pIndex->fShared = fShared; + pIndex->fReadonly = FALSE; + pIndex->szFileName = hb_strdup( szFileName ); + pIndex->fDelete = fTemporary; + if( fTemporary ) + pIndex->szRealName = hb_strdup( szTempFile ); + + if ( !fNewFile ) + { + /* index file is corrupted? */ + if ( ! hb_cdxIndexLoad( pIndex, szCpndTagName ) ) + { + /* TODO: What should be default? */ + /* + hb_cdxIndexFree( pIndex ); + hb_fsClose( hFile ); + hFile = FS_ERROR; + hb_cdxErrorRT( pArea, EG_CORRUPTION, EDBF_CORRUPT, + szFileName, hb_fsError(), EF_CANDEFAULT ); + */ + hb_cdxIndexFreeTags( pIndex ); + fNewFile = TRUE; + } + } + } + + if ( hFile == FS_ERROR ) + { + hb_vmDestroyBlockOrMacro( pKeyExp ); + if ( pForExp != NULL ) + hb_vmDestroyBlockOrMacro( pForExp ); + return FAILURE; + } + } + + 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 ); + pIndex->fChanged = TRUE; + hb_cdxIndexDropAvailPage( pIndex ); + if ( pIndex->pCompound != NULL ) + hb_cdxTagFree( pIndex->pCompound ); + pIndex->nextAvail = pIndex->freePage = 0; + hb_cdxIndexCreateStruct( pIndex, szCpndTagName ); + } + + pTag = hb_cdxIndexAddTag( pIndex, szTagName, hb_itemGetCPtr( pOrderInfo->abExpr ), + pKeyExp, bType, uiLen, szFor, pForExp, + fAscend , pOrderInfo->fUnique, fCustom, FALSE ); + + if ( pArea->lpdbOrdCondInfo && ( !pArea->lpdbOrdCondInfo->fAll && + !pArea->lpdbOrdCondInfo->fAdditive ) ) + { +#ifdef HB_CDX_CLIP_AUTOPEN + hb_cdxOrdListClear( pArea, !hb_set.HB_SET_AUTOPEN, pIndex ); +#else + hb_cdxOrdListClear( pArea, !pArea->fHasTags || !hb_set.HB_SET_AUTOPEN, pIndex ); +#endif + } + hb_cdxIndexUnLockWrite( pIndex ); + /* Update DBF header */ + if( !pArea->fHasTags && !fOpenedIndex && !pIndex->fDelete && fProd ) + { + pArea->fHasTags = TRUE; + if ( !pArea->fReadonly && ( pArea->dbfHeader.bHasTags & 0x01 ) == 0 ) + { +#ifdef HB_CDX_CLIP_AUTOPEN + if ( hb_set.HB_SET_AUTOPEN ) +#endif + SELF_WRITEDBHEADER( ( AREAP ) pArea ); + } + } + else + { + fProd = FALSE; + } + + if( !fOpenedIndex ) + { + if ( fProd || pArea->lpIndexes == NULL ) + { + pIndex->pNext = pArea->lpIndexes; + 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; + + HB_TRACE(HB_TR_DEBUG, ("hb_cdxOrderDestroy(%p, %p)", pArea, pOrderInfo)); + + if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + if ( ! pArea->lpIndexes ) + return SUCCESS; + + if ( pOrderInfo->itmOrder ) + { + pTag = hb_cdxFindTag( pArea, pOrderInfo->itmOrder, pOrderInfo->atomBagName, &uiTag ); + if ( pTag ) + { + 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; + if ( !pArea->fReadonly && ( pArea->dbfHeader.bHasTags & 0x01 ) != 0 ) + { +#ifdef HB_CDX_CLIP_AUTOPEN + if ( hb_set.HB_SET_AUTOPEN ) +#endif + 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; + } + } + pIndex->fDelete = TRUE; + hb_cdxIndexFree( pIndex ); + } + if( uiTag < pArea->uiTag ) + pArea->uiTag--; + else if( uiTag == pArea->uiTag ) + pArea->uiTag = 0; + } + 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; + USHORT uiTag = 0; + + HB_TRACE(HB_TR_DEBUG, ("hb_cdxOrderInfo(%p, %hu, %p)", pArea, uiIndex, pOrderInfo)); + + switch( uiIndex ) + { + case DBOI_STRICTREAD: + if( pOrderInfo->itmResult ) + hb_itemClear( pOrderInfo->itmResult ); + else + pOrderInfo->itmResult = hb_itemNew( NULL ); + return SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_STRICTREAD, 0, pOrderInfo->itmResult ); + + case DBOI_OPTIMIZE: + if( pOrderInfo->itmResult ) + hb_itemClear( pOrderInfo->itmResult ); + else + pOrderInfo->itmResult = hb_itemNew( NULL ); + return SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_OPTIMIZE, 0, pOrderInfo->itmResult ); + + case DBOI_AUTOOPEN: + if( pOrderInfo->itmResult ) + hb_itemClear( pOrderInfo->itmResult ); + else + pOrderInfo->itmResult = hb_itemNew( NULL ); + return SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_AUTOOPEN, 0, pOrderInfo->itmResult ); + + case DBOI_AUTOORDER: + if( pOrderInfo->itmResult ) + hb_itemClear( pOrderInfo->itmResult ); + else + pOrderInfo->itmResult = hb_itemNew( NULL ); + return SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_AUTOORDER, 0, pOrderInfo->itmResult ); + + case DBOI_AUTOSHARE: + if( pOrderInfo->itmResult ) + hb_itemClear( pOrderInfo->itmResult ); + else + pOrderInfo->itmResult = hb_itemNew( NULL ); + return SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_AUTOSHARE, 0, pOrderInfo->itmResult ); + + case DBOI_BAGEXT: + if( pOrderInfo->itmResult ) + hb_itemClear( pOrderInfo->itmResult ); + else + pOrderInfo->itmResult = hb_itemNew( NULL ); + return SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_ORDBAGEXT, 0, pOrderInfo->itmResult ); + + case DBOI_EVALSTEP: + pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, + pArea->lpdbOrdCondInfo ? pArea->lpdbOrdCondInfo->lStep : 0 ); + return SUCCESS; + + case DBOI_KEYSINCLUDED: + pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, + pArea->pSort ? pArea->pSort->ulTotKeys : 0 ); + return SUCCESS; + + case DBOI_I_TAGNAME: + pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, + pArea->pSort ? pArea->pSort->pTag->szName : NULL ); + return SUCCESS; + + case DBOI_I_BAGNAME: + pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, + pArea->pSort ? pArea->pSort->pTag->pIndex->szFileName : NULL ); + return SUCCESS; + + case DBOI_ISREINDEX: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + pArea->pSort ? pArea->pSort->fReindex : FALSE ); + return SUCCESS; + + case DBOI_LOCKOFFSET: + case DBOI_HPLOCKING: + { + HB_FOFFSET ulPos, ulPool; + + hb_dbfLockIdxGetData( pArea->bLockType, &ulPos, &ulPool ); + if ( uiIndex == DBOI_LOCKOFFSET ) + pOrderInfo->itmResult = hb_itemPutNInt( pOrderInfo->itmResult, ulPos ); + else + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, ulPool > 0 ); + return SUCCESS; + } + + case DBOI_ORDERCOUNT: + { + LPCDXINDEX pIndex; + char *pszBag = hb_itemGetCLen( pOrderInfo->atomBagName ) > 0 ? + hb_itemGetCPtr( pOrderInfo->atomBagName ) : NULL; + pIndex = pszBag ? hb_cdxFindBag( pArea, pszBag ) : pArea->lpIndexes; + while ( pIndex ) + { + pTag = pIndex->TagList; + while ( pTag ) + { + ++uiTag; + pTag = pTag->pNext; + } + pIndex = pszBag ? NULL : pIndex->pNext; + } + pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, uiTag ); + return SUCCESS; + } + + case DBOI_BAGCOUNT: + { + LPCDXINDEX pIndex = pArea->lpIndexes; + while ( pIndex ) + { + ++uiTag; + pIndex = pIndex->pNext; + } + pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, uiTag ); + return SUCCESS; + } + + case DBOI_BAGNUMBER: + { + LPCDXINDEX pIndex = pArea->lpIndexes, pIndexSeek; + + if( hb_itemGetCLen( pOrderInfo->atomBagName ) > 0 ) + pIndexSeek = hb_cdxFindBag( pArea, + hb_itemGetCPtr( pOrderInfo->atomBagName ) ); + else + pIndexSeek = pIndex; + + if( pIndexSeek ) + { + ++uiTag; + do + { + if( pIndex == pIndexSeek ) + break; + ++uiTag; + pIndex = pIndex->pNext; + } + while ( pIndex ); + } + pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, + pIndex ? uiTag : 0 ); + return SUCCESS; + } + + case DBOI_BAGORDER: + { + LPCDXINDEX pIndex = pArea->lpIndexes, pIndexSeek; + + if( hb_itemGetCLen( pOrderInfo->atomBagName ) > 0 ) + pIndexSeek = hb_cdxFindBag( pArea, + hb_itemGetCPtr( pOrderInfo->atomBagName ) ); + else + pIndexSeek = pIndex; + + if( pIndexSeek ) + { + ++uiTag; + do + { + if( pIndex == pIndexSeek ) + break; + pTag = pIndex->TagList; + while ( pTag ) + { + ++uiTag; + pTag = pTag->pNext; + } + pIndex = pIndex->pNext; + } + while ( pIndex ); + } + pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, + pIndex ? uiTag : 0 ); + return SUCCESS; + } + } + + if( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + if( pOrderInfo->itmOrder ) + { + pTag = hb_cdxFindTag( pArea, pOrderInfo->itmOrder, pOrderInfo->atomBagName, &uiTag ); + } + else + { + uiTag = pArea->uiTag; + pTag = hb_cdxGetTagByNumber( pArea, uiTag ); + } + + switch( uiIndex ) + { + case DBOI_CONDITION: + pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, ( pTag ? pTag->ForExpr : "" ) ); + if ( pTag && pOrderInfo->itmNewVal && HB_IS_STRING( pOrderInfo->itmNewVal ) ) + { + if ( pTag->ForExpr != NULL ) + { + hb_xfree( pTag->ForExpr ); + pTag->ForExpr = NULL; + } + if ( pTag->pForItem != NULL ) + { + hb_vmDestroyBlockOrMacro( pTag->pForItem ); + pTag->pForItem = NULL; + } + if ( hb_itemGetCLen( pOrderInfo->itmNewVal ) > 0 ) + { + char * pForExpr = hb_itemGetCPtr( pOrderInfo->itmNewVal ); + + if ( SELF_COMPILE( ( AREAP ) pArea, ( BYTE *) pForExpr ) == SUCCESS ) + { + PHB_ITEM pForItem = pArea->valResult; + pArea->valResult = NULL; + if ( SELF_EVALBLOCK( ( AREAP ) pArea, pForItem ) == SUCCESS ) + { + if ( hb_itemType( pArea->valResult ) == HB_IT_LOGICAL ) + { + pTag->pForItem = pForItem; + pForItem = NULL; + } + hb_itemRelease( pArea->valResult ); + pArea->valResult = NULL; + } + if ( pForItem ) + hb_vmDestroyBlockOrMacro( pForItem ); + } + } + } + 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; + + /* TODO: is this ok? DBOI_RECNO == DBOI_KEYNORAW ? No, it isn't. */ + /* case DBOI_RECNO: */ + case DBOI_KEYNORAW: + if ( pOrderInfo->itmNewVal && HB_IS_NUMERIC( pOrderInfo->itmNewVal ) ) + { + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + hb_cdxDBOIKeyGoto( pArea, pTag, + hb_itemGetNL( pOrderInfo->itmNewVal ), FALSE ) == SUCCESS ); + } + else + 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_RELKEYPOS: + if ( pOrderInfo->itmNewVal && HB_IS_NUMERIC( pOrderInfo->itmNewVal ) ) + hb_cdxDBOISetRelKeyPos( pArea, pTag, + hb_itemGetND( pOrderInfo->itmNewVal ) ); + else + pOrderInfo->itmResult = hb_itemPutND( pOrderInfo->itmResult, + hb_cdxDBOIGetRelKeyPos( pArea, pTag ) ); + break; + + case DBOI_FINDREC: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + hb_cdxDBOIFindRec( pArea, pTag, + hb_itemGetNL( pOrderInfo->itmNewVal ), FALSE ) ); + break; + + case DBOI_FINDRECCONT: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + hb_cdxDBOIFindRec( pArea, pTag, + hb_itemGetNL( pOrderInfo->itmNewVal ), TRUE ) ); + break; + + case DBOI_SKIPUNIQUE: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + hb_cdxDBOISkipUnique( 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_SKIPWILD: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + hb_cdxDBOISkipWild( pArea, pTag, TRUE, pOrderInfo->itmNewVal ) ); + break; + + case DBOI_SKIPWILDBACK: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + hb_cdxDBOISkipWild( pArea, pTag, FALSE, pOrderInfo->itmNewVal ) ); + break; + + case DBOI_SKIPREGEX: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + hb_cdxDBOISkipRegEx( pArea, pTag, TRUE, pOrderInfo->itmNewVal ) ); + break; + + case DBOI_SKIPREGEXBACK: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + hb_cdxDBOISkipRegEx( pArea, pTag, FALSE, pOrderInfo->itmNewVal ) ); + break; + + case DBOI_SCOPEEVAL: + if ( pTag && pOrderInfo->itmNewVal && + hb_arrayLen( pOrderInfo->itmNewVal ) == DBRMI_SIZE && + hb_arrayGetPtr( pOrderInfo->itmNewVal, DBRMI_FUNCTION ) != NULL ) + { + pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, + hb_cdxDBOIScopeEval( pTag, ( HB_EVALSCOPE_FUNC ) + hb_arrayGetPtr( pOrderInfo->itmNewVal, DBRMI_FUNCTION ), + hb_arrayGetPtr( pOrderInfo->itmNewVal, DBRMI_PARAM ), + hb_arrayGetItemPtr( pOrderInfo->itmNewVal, DBRMI_LOVAL ), + hb_arrayGetItemPtr( pOrderInfo->itmNewVal, DBRMI_HIVAL ) ) ); + } + else + { + /* TODO: RT error */ + ; + } + 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_FILEHANDLE: + pOrderInfo->itmResult = hb_itemPutNInt( pOrderInfo->itmResult, pTag ? pTag->pIndex->hFile : FS_ERROR ); + break; + + case DBOI_ISCOND: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, pTag && pTag->ForExpr != NULL ); + break; + + case DBOI_ISDESC: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, pTag && !pTag->UsrAscend ); + if ( pTag && pOrderInfo->itmNewVal && HB_IS_LOGICAL( pOrderInfo->itmNewVal ) ) + { + pTag->UsrAscend = ! hb_itemGetL( pOrderInfo->itmNewVal ); + pTag->curKeyState &= ~( CDX_CURKEY_RAWPOS | CDX_CURKEY_LOGPOS ); + } + break; + + case DBOI_UNIQUE: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, ( pTag ? pTag->UniqueKey || pTag->UsrUnique : FALSE ) ); + if ( pTag && pOrderInfo->itmNewVal && HB_IS_LOGICAL( pOrderInfo->itmNewVal ) && !pTag->UniqueKey ) + { + pTag->UsrUnique = hb_itemGetL( pOrderInfo->itmNewVal ); + pTag->curKeyState &= ~( CDX_CURKEY_RAWPOS | CDX_CURKEY_LOGPOS | + CDX_CURKEY_RAWCNT | CDX_CURKEY_LOGCNT ); + } + 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: + pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, pTag ? pTag->uiLen : 0 ); + break; + + case DBOI_KEYDEC: + /* there is no fixed number of decimal places for numeric keys + in CDX format */ + pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, 0 ); + break; + + case DBOI_KEYVAL: + hb_itemClear( pOrderInfo->itmResult ); + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + if ( pTag && pArea->fPositioned ) + { + if ( pTag->CurKey->rec != pArea->ulRecNo ) + { + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxCurKeyRefresh( pArea, pTag ); + hb_cdxIndexUnLockRead( pTag->pIndex ); + } + if ( pTag->CurKey->rec == pArea->ulRecNo ) + pOrderInfo->itmResult = hb_cdxKeyGetItem( pTag->CurKey, + pOrderInfo->itmResult, pTag, TRUE ); + } + break; + + case DBOI_SCOPETOP: + if ( pTag ) + { + if ( pOrderInfo->itmResult ) + hb_cdxTagGetScope( pTag, 0, pOrderInfo->itmResult ); + if ( pOrderInfo->itmNewVal ) + hb_cdxTagSetScope( pTag, 0, pOrderInfo->itmNewVal ); + } + else if ( pOrderInfo->itmResult ) + hb_itemClear( pOrderInfo->itmResult ); + break; + + case DBOI_SCOPEBOTTOM: + if ( pTag ) + { + if ( pOrderInfo->itmResult ) + hb_cdxTagGetScope( pTag, 1, pOrderInfo->itmResult ); + if ( pOrderInfo->itmNewVal ) + hb_cdxTagSetScope( pTag, 1, pOrderInfo->itmNewVal ); + } + else if ( pOrderInfo->itmResult ) + hb_itemClear( pOrderInfo->itmResult ); + break; + + case DBOI_SCOPESET: + if ( pTag ) + { + if ( pOrderInfo->itmNewVal ) + { + hb_cdxTagSetScope( pTag, 0, pOrderInfo->itmNewVal ); + hb_cdxTagSetScope( pTag, 1, pOrderInfo->itmNewVal ); + } + } + if ( pOrderInfo->itmResult ) + hb_itemClear( pOrderInfo->itmResult ); + break; + + case DBOI_SCOPETOPCLEAR: + if ( pTag ) + { + if ( pOrderInfo->itmResult ) + hb_cdxTagGetScope( pTag, 0, pOrderInfo->itmResult ); + hb_cdxTagClearScope( pTag, 0 ); + } + else if ( pOrderInfo->itmResult ) + hb_itemClear( pOrderInfo->itmResult ); + break; + + case DBOI_SCOPEBOTTOMCLEAR: + if ( pTag ) + { + if ( pOrderInfo->itmResult ) + hb_cdxTagGetScope( pTag, 1, pOrderInfo->itmResult ); + hb_cdxTagClearScope( pTag, 1 ); + } + else if ( pOrderInfo->itmResult ) + hb_itemClear( pOrderInfo->itmResult ); + break; + + case DBOI_SCOPECLEAR: + if ( pTag ) + { + hb_cdxTagClearScope( pTag, 0 ); + hb_cdxTagClearScope( pTag, 1 ); + } + if ( pOrderInfo->itmResult ) + hb_itemClear( pOrderInfo->itmResult ); + break; + + case DBOI_CUSTOM: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, ( pTag ? pTag->Custom : FALSE ) ); + if ( pOrderInfo->itmNewVal && HB_IS_LOGICAL( pOrderInfo->itmNewVal ) + && hb_itemGetL( pOrderInfo->itmNewVal ) ) + { + pTag->Custom = TRUE; + } + break; + + /* TODO: */ + /* + case DBOI_TEMPLATE: + case DBOI_MULTIKEY: + case DBOI_PARTIAL: + case DBOI_CHGONLY: + */ + + case DBOI_KEYADD: + if ( !pTag ) + { + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, FALSE ); + } + else + { + if ( pTag->Custom ) + { + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + if( !pArea->fPositioned || + ( pTag->pForItem && + !hb_cdxEvalCond( pArea, pTag->pForItem, TRUE ) ) ) + { + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, FALSE ); + } + else + { + 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 ); + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + hb_cdxTagKeyAdd( pTag, pKey ) ); + hb_cdxIndexUnLockWrite( pTag->pIndex ); + hb_cdxKeyFree( pKey ); + } + } + else + { + hb_cdxErrorRT( pArea, 0, 1052, NULL, 0, 0 ); + } + } + break; + + case DBOI_KEYDELETE: + if ( !pTag ) + { + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, FALSE ); + } + else + { + if ( pTag->Custom ) + { + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + if( !pArea->fPositioned || + ( pTag->pForItem && + !hb_cdxEvalCond( pArea, pTag->pForItem, TRUE ) ) ) + { + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, FALSE ); + } + else + { + 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 ); + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + hb_cdxTagKeyDel( pTag, pKey ) ); + hb_cdxIndexUnLockWrite( pTag->pIndex ); + hb_cdxKeyFree( pKey ); + } + } + else + { + hb_cdxErrorRT( pArea, 0, 1052, NULL, 0, 0 ); + } + } + break; + + case DBOI_READLOCK: + if( pTag ) + { + if( hb_itemType( pOrderInfo->itmNewVal ) == HB_IT_LOGICAL ) + { + if( hb_itemGetL( pOrderInfo->itmNewVal ) ) + hb_cdxIndexLockRead( pTag->pIndex ); + else + hb_cdxIndexUnLockRead( pTag->pIndex ); + } + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + pTag->pIndex->lockRead > 0 ); + } + else + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, FALSE ); + break; + + case DBOI_WRITELOCK: + if( pTag ) + { + if( hb_itemType( pOrderInfo->itmNewVal ) == HB_IT_LOGICAL ) + { + if( hb_itemGetL( pOrderInfo->itmNewVal ) ) + hb_cdxIndexLockWrite( pTag->pIndex ); + else + hb_cdxIndexUnLockWrite( pTag->pIndex ); + } + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + pTag->pIndex->lockWrite > 0 ); + } + else + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, FALSE ); + break; + + case DBOI_UPDATECOUNTER: + if( pTag ) + { + /* refresh update counter */ + if( hb_cdxIndexLockRead( pTag->pIndex ) ) + hb_cdxIndexUnLockRead( pTag->pIndex ); + pOrderInfo->itmResult = hb_itemPutNInt( pOrderInfo->itmResult, + pTag->pIndex->ulVersion ); + } + else + pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, 0 ); + break; + + case DBOI_SHARED: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + pTag && pTag->pIndex->fShared ); + break; + + case DBOI_ISREADONLY: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + pTag && pTag->pIndex->fReadonly ); + break; + + case DBOI_ISMULTITAG: + case DBOI_ISSORTRECNO: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, pTag != NULL ); + break; + + case DBOI_LARGEFILE: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, FALSE ); + break; + + default: + return SUPER_ORDINFO( ( AREAP ) pArea, uiIndex, pOrderInfo ); + + } + return SUCCESS; +} + +/* ( DBENTRYP_V ) hb_cdxClearFilter */ +static ERRCODE hb_cdxClearFilter( CDXAREAP pArea ) +{ + hb_cdxClearLogPosInfo( pArea ); + // Limpiamos filtro tipo array + if ( pArea->dbfi.lpvCargo ) + { + hb_xfree( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap ); + hb_xfree( pArea->dbfi.lpvCargo ); + pArea->dbfi.lpvCargo = NULL; + } + return SUPER_CLEARFILTER( ( AREAP ) pArea ); +} + +/* ( DBENTRYP_V ) hb_cdxClearLocate : NULL */ +/* ( DBENTRYP_V ) hb_cdxClearScope : NULL */ + +/* ( DBENTRYP_VPLP ) hb_cdxCountScope */ +static ERRCODE hb_cdxCountScope( CDXAREAP pArea, void * pPtr, LONG * plRec ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_cdxCountScope(%p, %p, %p)", pArea, pPtr, plRec)); + + if ( pPtr == NULL ) + { + return SUCCESS; + } + return SUPER_COUNTSCOPE( ( AREAP ) pArea, pPtr, plRec ); +} + +/* ( DBENTRYP_I ) hb_cdxFilterText : NULL */ +/* ( DBENTRYP_SI ) hb_cdxScopeInfo : NULL */ + +/* ( DBENTRYP_VFI ) hb_cdxSetFilter */ +static ERRCODE hb_cdxSetFilter( CDXAREAP pArea, LPDBFILTERINFO pFilterInfo ) +{ + ULONG ulRecCount = 0, ulLogKeyCount = 0; + LPCDXTAG pTag; + PHB_ITEM pResult; + + HB_SYMBOL_UNUSED( ulLogKeyCount ); + + hb_cdxClearLogPosInfo( pArea ); + + if ( SUPER_SETFILTER( ( AREAP ) pArea, pFilterInfo ) != SUCCESS ) + return FAILURE; + + pArea->dbfi.fOptimized = hb_set.HB_SET_OPTIMIZE; + + if ( pArea->dbfi.fOptimized ) + { + pArea->dbfi.lpvCargo = hb_xgrab( sizeof( BM_FILTER ) ); + memset( pArea->dbfi.lpvCargo, 0, sizeof( BM_FILTER ) ); + + pArea->dbfi.fFilter = FALSE; + + pTag = hb_cdxGetActiveTag( pArea ); + SELF_RECCOUNT( ( AREAP ) pArea, &ulRecCount ); + ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->Size = ulRecCount; + ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap = (ULONG *) hb_xgrab( sizeof(ULONG) * (((ulRecCount+1) >> 5) + 1 ) ); + memset( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, 0, sizeof(ULONG) * (((ulRecCount+1) >> 5) + 1 ) ); + + if ( pTag ) // with active index + { + if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + hb_cdxTagGoTop( pTag ); + ulLogKeyCount = 0; + while ( !pTag->TagEOF ) + { + if( pArea->ulRecNo != pTag->CurKey->rec || pArea->lpdbPendingRel ) + SELF_GOTO( (AREAP) pArea, pTag->CurKey->rec ); + pResult = hb_vmEvalBlock( pArea->dbfi.itmCobExpr ); + if ( HB_IS_LOGICAL( pResult ) && hb_itemGetL( pResult ) ) + { + BM_SetBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ulRecCount, pTag->CurKey->rec ); + ulLogKeyCount++; + } + hb_cdxTagSkipNext( pTag ); + } + hb_cdxIndexUnLockRead( pTag->pIndex ); + pTag->curKeyState &= ~( CDX_CURKEY_RAWPOS | CDX_CURKEY_RAWCNT ); + CURKEY_SETLOGCNT( pTag, ulLogKeyCount ); + } + else + { + SELF_GOTOP( ( AREAP ) pArea ); + while ( ! pArea->fEof ) + { + pResult = hb_vmEvalBlock( pArea->dbfi.itmCobExpr ); + if ( HB_IS_LOGICAL( pResult ) && hb_itemGetL( pResult ) ) + BM_SetBit( ( ( LPBM_FILTER ) pArea->dbfi.lpvCargo)->rmap, ulRecCount, (pArea)->ulRecNo ); + SELF_SKIP( ( AREAP ) pArea, 1 ); + } + } + pArea->dbfi.fFilter = TRUE; + } + + return SUCCESS; +} + +/* ( DBENTRYP_VLO ) hb_cdxSetLocate : NULL */ +/* ( DBENTRYP_VOS ) hb_cdxSetScope : NULL */ +/* ( DBENTRYP_VPL ) hb_cdxSkipScope : NULL */ +/* ( DBENTRYP_B ) hb_cdxLocate : 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_SVPB ) hb_cdxPutValueFile : NULL */ + +/* ( DBENTRYP_V ) hb_cdxReadDBHeader : NULL */ +/* ( DBENTRYP_V ) hb_cdxWriteDBHeader : NULL */ +/* ( DBENTRYP_SVP ) hb_cdxWhoCares : NULL */ + +/* + * Retrieve (set) information about RDD + * ( DBENTRYP_RSLV ) hb_fptFieldInfo + */ +static ERRCODE hb_cdxRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, PHB_ITEM pItem ) +{ + LPDBFDATA pData; + + HB_TRACE(HB_TR_DEBUG, ("hb_cdxRddInfo(%p, %hu, %lu, %p)", pRDD, uiIndex, ulConnect, pItem)); + + pData = ( LPDBFDATA ) pRDD->lpvCargo; + + switch( uiIndex ) + { + case RDDI_ORDBAGEXT: + case RDDI_ORDEREXT: + case RDDI_ORDSTRUCTEXT: + { + char * szNew = hb_itemGetCPtr( pItem ); + + if( szNew[0] == '.' && szNew[1] ) + szNew = hb_strdup( szNew ); + else + szNew = NULL; + + hb_itemPutC( pItem, pData->szIndexExt[ 0 ] ? pData->szIndexExt : CDX_INDEXEXT ); + if( szNew ) + { + hb_strncpy( pData->szIndexExt, szNew, HB_MAX_FILE_EXT ); + hb_xfree( szNew ); + } + break; + } + + case RDDI_MULTIKEY: + case RDDI_MULTITAG: + case RDDI_SORTRECNO: + case RDDI_STRUCTORD: + case RDDI_STRICTSTRUCT: + hb_itemPutL( pItem, TRUE ); + break; + + default: + return SUPER_RDDINFO( pRDD, uiIndex, ulConnect, pItem ); + + } + + return SUCCESS; +} + + + +/* ######################################################################### */ + +static int hb_cdxQuickSortCompare( LPCDXSORTINFO pSort, BYTE * pKey1, BYTE * pKey2 ) +{ + int i, iLen = pSort->keyLen; + + i = hb_cdxValCompare( pSort->pTag, pKey1, iLen, pKey2, iLen, TRUE ); + + if ( i == 0 ) + { + i = ( HB_GET_LE_UINT32( pKey1 + iLen ) < HB_GET_LE_UINT32( pKey2 + iLen ) ) ? -1 : 1; + } + + return i; +} + +static BOOL hb_cdxQSort( LPCDXSORTINFO pSort, BYTE * pSrc, BYTE * pBuf, LONG lKeys ) +{ + if ( lKeys > 1 ) + { + int iLen = pSort->keyLen + 4; + LONG l1, l2; + BYTE * pPtr1, * pPtr2, *pDst; + BOOL f1, f2; + + l1 = lKeys >> 1; + l2 = lKeys - l1; + pPtr1 = &pSrc[ 0 ]; + pPtr2 = &pSrc[ l1 * iLen ]; + + f1 = hb_cdxQSort( pSort, pPtr1, &pBuf[ 0 ], l1 ); + f2 = hb_cdxQSort( pSort, pPtr2, &pBuf[ l1 * iLen ], l2 ); + if ( f1 ) + { + pDst = pBuf; + } + else + { + pDst = pSrc; + pPtr1 = &pBuf[ 0 ]; + } + if ( !f2 ) + { + pPtr2 = &pBuf[ l1 * iLen ]; + } + while ( l1 > 0 && l2 > 0 ) + { + if ( hb_cdxQuickSortCompare( pSort, pPtr1, pPtr2 ) <= 0 ) + { + memcpy( pDst, pPtr1, iLen ); + pPtr1 += iLen; + l1--; + } + else + { + memcpy( pDst, pPtr2, iLen ); + pPtr2 += iLen; + l2--; + } + pDst += iLen; + } + if ( l1 > 0 ) + { + memcpy( pDst, pPtr1, iLen * l1 ); + } + else if ( l2 > 0 && f1 == f2 ) + { + memcpy( pDst, pPtr2, iLen * l2 ); + } + return !f1; + } + return TRUE; +} + +static void hb_cdxSortSortPage( LPCDXSORTINFO pSort ) +{ + ULONG ulSize = pSort->ulKeys * ( pSort->keyLen + 4 ); +#ifdef HB_CDX_DBGTIME + cdxTimeIdxBld -= hb_cdxGetTime(); +#endif + if ( !hb_cdxQSort( pSort, pSort->pKeyPool, &pSort->pKeyPool[ ulSize ], pSort->ulKeys ) ) + { + memcpy( pSort->pKeyPool, &pSort->pKeyPool[ ulSize ], ulSize ); + } +#ifdef HB_CDX_DBGTIME + cdxTimeIdxBld += hb_cdxGetTime(); +#endif +} + +static void hb_cdxSortAddNodeKey( LPCDXSORTINFO pSort, int iLevel, BYTE *pKeyVal, ULONG ulRec, ULONG ulPage ) +{ + LPCDXPAGE pPage; + BOOL fNew; + int iLen = pSort->keyLen, iDup = 0, iTrl = 0, iTmp, iPos; + BYTE *pTmp; + + pPage = pSort->NodeList[ iLevel ]; + if ( iLevel == 0 ) + { + while ( iTrl < iLen && pKeyVal[ iLen - iTrl - 1 ] == pSort->bTrl ) + { + iTrl++; + } + if ( pPage != NULL && pPage->iKeys > 0 ) + { +#ifdef HB_CDX_PACKTRAIL + int iMax = iLen - iTrl; +#else + int iMax = iLen - HB_MAX( iTrl, pSort->iLastTrl ); +#endif + while ( pKeyVal[ iDup ] == pSort->pLastKey[ iDup ] && iDup < iMax ) + { + iDup++; + } + } +#ifndef HB_CDX_PACKTRAIL + pSort->iLastTrl = iTrl; +#endif + } + if( pPage == NULL ) + { + fNew = TRUE; + } + else + { + if ( iLevel == 0 ) + { + fNew = ( pPage->iFree - ( iLen - iDup - iTrl ) - pPage->ReqByte ) < 0; + } + else + { + fNew = ( pSort->NodeList[ iLevel ]->iKeys >= pSort->pTag->MaxKeys ); + } + } + + if( fNew ) + { + pPage = hb_cdxPageNew( pSort->pTag, NULL, 0 ); + pPage->PageType = ( iLevel == 0 ) ? CDX_NODE_LEAF : CDX_NODE_BRANCH; + if ( iLevel == 0 ) + { + hb_cdxPageLeafInitSpace( pPage ); + iDup = 0; + while ( pSort->ulMaxRec > pPage->RNMask ) + { + pPage->ReqByte++; + pPage->RNBits += 8; + pPage->RNMask = ( pPage->RNMask << 8 ) | 0xFF; + } + } + if ( pSort->NodeList[ iLevel ] != NULL ) + { + pSort->NodeList[ iLevel ]->Right = pPage->Page; + pPage->Left = pSort->NodeList[ iLevel ]->Page; + if ( iLevel == 0 ) + { +#ifdef HB_CDX_DBGCODE_EXT + hb_cdxPageCheckDupTrlRaw( pSort->NodeList[ iLevel ] ); +#endif + hb_cdxSortAddNodeKey( pSort, iLevel + 1, pSort->pLastKey, pSort->ulLastRec, pSort->NodeList[ iLevel ]->Page ); + } + else + { + iPos = ( pSort->NodeList[ iLevel ]->iKeys - 1 ) * ( iLen + 8 ); + pTmp = &pSort->NodeList[ iLevel ]->node.intNode.keyPool[ iPos ]; + hb_cdxSortAddNodeKey( pSort, iLevel + 1, pTmp, HB_GET_BE_UINT32( &pTmp[ iLen ] ), pSort->NodeList[ iLevel ]->Page ); + } + hb_cdxPageFree( pSort->NodeList[ iLevel ], TRUE ); + } + pSort->NodeList[ iLevel ] = pPage; + } + if ( iLevel == 0 ) + { + iPos = pPage->iKeys * pPage->ReqByte; + hb_cdxSetLeafRecord( &pPage->node.extNode.keyPool[ iPos ], + ulRec, iDup, iTrl, + pPage->ReqByte, pPage->DCBits, pPage->TCBits ); + iTmp = iLen - iDup - iTrl; + if ( iTmp > 0 ) + { + memcpy( &pPage->node.extNode.keyPool[ pPage->iFree + iPos - iTmp ], + &pKeyVal[ iDup ], iTmp ); + } + pPage->iFree -= iTmp + pPage->ReqByte; + pPage->iKeys++; +#ifdef HB_CDX_DBGCODE_EXT + hb_cdxPageCheckDupTrlRaw( pSort->NodeList[ iLevel ] ); +#endif + } + else + { + pPage = pSort->NodeList[ iLevel ]; + iPos = pPage->iKeys * ( iLen + 8 ); + pTmp = &pPage->node.intNode.keyPool[ iPos ]; + memcpy( pTmp, pKeyVal, iLen ); + HB_PUT_BE_UINT32( &pTmp[ iLen ], ulRec ); + HB_PUT_BE_UINT32( &pTmp[ iLen + 4 ], ulPage ); + pPage->iKeys++; + } +} + +static void hb_cdxSortWritePage( LPCDXSORTINFO pSort ) +{ + ULONG ulSize = pSort->ulKeys * ( pSort->keyLen + 4 ); + + hb_cdxSortSortPage( pSort ); + + if ( pSort->hTempFile == FS_ERROR ) + { + BYTE szName[ _POSIX_PATH_MAX + 1 ]; + pSort->hTempFile = hb_fsCreateTemp( NULL, NULL, FC_NORMAL, szName ); + if ( pSort->hTempFile == FS_ERROR ) + { + hb_errInternal( 9999, "hb_cdxSortWritePage: Can't create temporary file.", "", "" ); + } + pSort->szTempFileName = hb_strdup( ( char * ) szName ); + } + pSort->pSwapPage[ pSort->ulCurPage ].ulKeys = pSort->ulKeys; + pSort->pSwapPage[ pSort->ulCurPage ].nOffset = hb_fsSeekLarge( pSort->hTempFile, 0, FS_END ); + if ( hb_fsWriteLarge( pSort->hTempFile, pSort->pKeyPool, ulSize ) != ulSize ) + { + hb_errInternal( 9999, "hb_cdxSortWritePage: Write error in temporary file.", "", "" ); + } + pSort->ulKeys = 0; + pSort->ulCurPage++; +} + +static void hb_cdxSortGetPageKey( LPCDXSORTINFO pSort, ULONG ulPage, + BYTE ** pKeyVal, ULONG *pulRec ) +{ + int iLen = pSort->keyLen; + + if ( pSort->pSwapPage[ ulPage ].ulKeyBuf == 0 ) + { + ULONG ulKeys = HB_MIN( pSort->ulPgKeys, pSort->pSwapPage[ ulPage ].ulKeys ); + ULONG ulSize = ulKeys * ( iLen + 4 ); + + if ( hb_fsSeekLarge( pSort->hTempFile, pSort->pSwapPage[ ulPage ].nOffset, SEEK_SET ) != pSort->pSwapPage[ ulPage ].nOffset || + hb_fsReadLarge( pSort->hTempFile, pSort->pSwapPage[ ulPage ].pKeyPool, ulSize ) != ulSize ) + { + hb_errInternal( 9999, "hb_cdxSortGetPageKey: Read error from temporary file.", "", "" ); + } + pSort->pSwapPage[ ulPage ].nOffset += ulSize; + pSort->pSwapPage[ ulPage ].ulKeyBuf = ulKeys; + pSort->pSwapPage[ ulPage ].ulCurKey = 0; + } + *pKeyVal = &pSort->pSwapPage[ ulPage ].pKeyPool[ pSort->pSwapPage[ ulPage ].ulCurKey * ( iLen + 4 ) ]; + *pulRec = HB_GET_LE_UINT32( *pKeyVal + iLen ); +} + +#ifdef HB_CDX_NEW_SORT +static void hb_cdxSortOrderPages( LPCDXSORTINFO pSort ) +{ + int iLen = pSort->keyLen, i; + LONG l, r, m; + ULONG n, ulPage, ulRec; + BYTE *pKey = NULL, *pTmp; + + pSort->ulFirst = 0; + pSort->pSortedPages = ( ULONG * ) hb_xgrab( pSort->ulPages * sizeof( ULONG ) ); + pSort->pSortedPages[ 0 ] = 0; + + if ( pSort->ulTotKeys > 0 ) + { + for ( n = 0; n < pSort->ulPages; n++ ) + { + hb_cdxSortGetPageKey( pSort, n, &pKey, &ulRec ); + l = 0; + r = n - 1; + while ( l <= r ) + { + m = ( l + r ) >> 1; + ulPage = pSort->pSortedPages[ m ]; + pTmp = &pSort->pSwapPage[ ulPage ].pKeyPool[ pSort->pSwapPage[ ulPage ].ulCurKey * ( iLen + 4 ) ]; + i = hb_cdxValCompare( pSort->pTag, pKey, iLen, pTmp, iLen, TRUE ); + if ( i == 0 ) + i = ( ulRec < HB_GET_LE_UINT32( &pTmp[ iLen ] ) ) ? -1 : 1; + if ( i > 0 ) + l = m + 1; + else + r = m - 1; + } + for ( r = n; r > l; r-- ) + pSort->pSortedPages[ r ] = pSort->pSortedPages[ r - 1 ]; + pSort->pSortedPages[ l ] = n; + } + } +} + +static BOOL hb_cdxSortKeyGet( LPCDXSORTINFO pSort, BYTE ** pKeyVal, ULONG *pulRec ) +{ + int iLen = pSort->keyLen, i; + LONG l, r, m; + ULONG ulPage; + + ulPage = pSort->pSortedPages[ pSort->ulFirst ]; + + /* check if first page has some keys yet */ + if ( pSort->pSwapPage[ ulPage ].ulKeys > 0 ) + { + BYTE *pKey, *pTmp; + ULONG ulRec; + + /* + * last key was taken from this page - we have to resort it. + * This is done intentionally here to be sure that the key + * value return by this function will not be overwritten by + * next keys in page read from temporary file in function + * hb_cdxSortGetPageKey() - please do not move this part down + * even it seems to be correct + */ + hb_cdxSortGetPageKey( pSort, ulPage, &pKey, &ulRec ); + + l = pSort->ulFirst + 1; + r = pSort->ulPages - 1; + while ( l <= r ) + { + m = ( l + r ) >> 1; + ulPage = pSort->pSortedPages[ m ]; + pTmp = &pSort->pSwapPage[ ulPage ].pKeyPool[ pSort->pSwapPage[ ulPage ].ulCurKey * ( iLen + 4 ) ]; + i = hb_cdxValCompare( pSort->pTag, pKey, iLen, pTmp, iLen, TRUE ); + if ( i == 0 ) + i = ( ulRec < HB_GET_LE_UINT32( &pTmp[ iLen ] ) ) ? -1 : 1; + + if ( i > 0 ) + l = m + 1; + else + r = m - 1; + } + if ( l > ( LONG ) pSort->ulFirst + 1 ) + { + ulPage = pSort->pSortedPages[ pSort->ulFirst ]; + for ( r = pSort->ulFirst + 1; r < l; r++ ) + pSort->pSortedPages[ r - 1 ] = pSort->pSortedPages[ r ]; + pSort->pSortedPages[ l - 1 ] = ulPage; + } + } + else + { + pSort->ulFirst++; + } + if ( pSort->ulFirst < pSort->ulPages ) + { + ulPage = pSort->pSortedPages[ pSort->ulFirst ]; + hb_cdxSortGetPageKey( pSort, ulPage, pKeyVal, pulRec ); + pSort->pSwapPage[ ulPage ].ulCurKey++; + pSort->pSwapPage[ ulPage ].ulKeys--; + pSort->pSwapPage[ ulPage ].ulKeyBuf--; + return TRUE; + } + return FALSE; +} + +#else + +static BOOL hb_cdxSortKeyGet( LPCDXSORTINFO pSort, BYTE ** pKeyVal, ULONG *pulRec ) +{ + int i, iLen = pSort->keyLen; + ULONG ulPage, ulKeyPage = 0, ulRec = 0, ulRecTmp; + BYTE *pKey = NULL, *pTmp; + + for ( ulPage = 0; ulPage < pSort->ulPages; ulPage++ ) + { + if ( pSort->pSwapPage[ ulPage ].ulKeys > 0 ) + { + hb_cdxSortGetPageKey( pSort, ulPage, &pTmp, &ulRecTmp ); + if ( ! pKey ) + { + i = 1; + } + else + { + i = hb_cdxValCompare( pSort->pTag, pKey, iLen, pTmp, iLen, TRUE ); + if ( i == 0 ) + { + i = ( ulRec < ulRecTmp ) ? -1 : 1; + } + } + if ( i > 0 ) + { + pKey = pTmp; + ulRec = ulRecTmp; + ulKeyPage = ulPage; + } + } + } + if ( pKey ) + { + pSort->pSwapPage[ ulKeyPage ].ulCurKey++; + pSort->pSwapPage[ ulKeyPage ].ulKeys--; + pSort->pSwapPage[ ulKeyPage ].ulKeyBuf--; + *pulRec = ulRec; + *pKeyVal = pKey; + return TRUE; + } + return FALSE; +} + +#endif + +static void hb_cdxSortKeyAdd( LPCDXSORTINFO pSort, ULONG ulRec, BYTE * pKeyVal, int iKeyLen ) +{ + int iLen = pSort->keyLen; + BYTE *pDst; + + if ( pSort->ulKeys >= pSort->ulPgKeys ) + { + hb_cdxSortWritePage( pSort ); + } + pDst = &pSort->pKeyPool[ pSort->ulKeys * ( iLen + 4 ) ]; + + if ( iLen > iKeyLen ) + { + memcpy( pDst, pKeyVal, iKeyLen ); + memset( &pDst[ iKeyLen ], pSort->bTrl, iLen - iKeyLen ); + } + else + { + memcpy( pDst, pKeyVal, iLen ); + } + HB_PUT_LE_UINT32( &pDst[ iLen ], ulRec ); + pSort->ulKeys++; + pSort->ulTotKeys++; +} + +static LPCDXSORTINFO hb_cdxSortNew( LPCDXTAG pTag, ULONG ulRecCount ) +{ + LPCDXSORTINFO pSort; + BYTE * pBuf; + int iLen = pTag->uiLen; + ULONG ulSize, ulMax, ulMin; + + if ( ulRecCount == 0 ) + ulRecCount = 1; + + pSort = ( LPCDXSORTINFO ) hb_xgrab( sizeof( CDXSORTINFO ) ); + memset( pSort, 0, sizeof( CDXSORTINFO ) ); + ulMax = ulMin = ( ULONG ) ceil( sqrt( ( double ) ulRecCount ) ); + ulSize = ( 1L << 20 ) / ( iLen + 4 ); + while ( ulMax < ulSize ) + ulMax <<= 1; + if ( ulMax > ulRecCount ) + ulMax = ulRecCount; + + do + { + ulSize = ulMax * ( iLen + 4 ); + pBuf = ( BYTE * ) hb_xalloc( ulSize << 2 ); + if ( pBuf ) + { + hb_xfree( pBuf ); + pBuf = ( BYTE * ) hb_xalloc( ulSize << 1 ); + } + else + { + ulMax >>= 1; + } + } + while ( ! pBuf && ulMax >= ulMin ); + + if ( ! pBuf ) + { + /* call hb_xgrab() to force out of memory error, + * though in multi process environment this call may return + * with success when other process free some memory + * (also the size of buf is reduced to absolute minimum). + * Sorry but I'm to lazy to implement indexing with smaller + * memory though it's possible - just simply I can even create + * index on-line by key adding like in normal update process. + * The memory necessary to index file is now ~ + * ~ (keySize+4+sizeof(CDXSWAPPAGE)) * sqrt(ulRecCount) * 2 + * so the maximum is for DBF with 2^32 records and keySize 240 ~ + * ~ 2^17 * 268 ~=~ 35 Mb + * this is not a problem for current computers and I do not see + * any way to use DBFs with four billions records and indexes with + * such long (240 bytes) keys on the old ones - they will be simply + * to slow. IMHO it's also better to signal out of memory here and + * force some system upgrades then run process which will have to + * take many hours, Druzus. + */ + ulMax = ulMin; + pBuf = ( BYTE * ) hb_xgrab( ( ulMax << 1 ) * ( iLen + 4 ) ); + } + + pSort->pTag = pTag; + pSort->hTempFile = FS_ERROR; + pSort->keyLen = iLen; + pSort->bTrl = pTag->bTrail; + pSort->fUnique = pTag->UniqueKey; + pSort->ulMaxKey = ulMax << 1; + pSort->ulPgKeys = ulMax; + pSort->ulMaxRec = ulRecCount; + pSort->pKeyPool = pBuf; + pSort->ulPages = ( ulRecCount + pSort->ulPgKeys - 1 ) / pSort->ulPgKeys; + pSort->pSwapPage = ( LPCDXSWAPPAGE ) hb_xgrab( sizeof( CDXSWAPPAGE ) * pSort->ulPages ); + memset( pSort->pSwapPage, 0, sizeof( CDXSWAPPAGE ) * pSort->ulPages ); + + return pSort; +} + +static void hb_cdxSortFree( LPCDXSORTINFO pSort ) +{ + if ( pSort->hTempFile != FS_ERROR ) + { + hb_fsClose( pSort->hTempFile ); + } + if ( pSort->szTempFileName ) + { + hb_fsDelete( (BYTE *) ( pSort->szTempFileName ) ); + hb_xfree( pSort->szTempFileName ); + } + if ( pSort->pKeyPool ) + { + hb_xfree( pSort->pKeyPool ); + } + if ( pSort->pSwapPage ) + { + hb_xfree( pSort->pSwapPage ); + } + if ( pSort->pRecBuff ) + { + hb_xfree( pSort->pRecBuff ); + } + if ( pSort->pSortedPages ) + { + hb_xfree( pSort->pSortedPages ); + } + hb_xfree( pSort ); +} + +static void hb_cdxSortOut( LPCDXSORTINFO pSort ) +{ + BOOL fUnique = pSort->fUnique, fNext; + ULONG ulPage, ulRec, ulKey; + BYTE * pKeyVal; + int iLen = pSort->keyLen, iLevel; + + pSort->ulPages = pSort->ulCurPage + 1; + pSort->ulPgKeys = pSort->ulMaxKey / pSort->ulPages; + /* + printf( "\r\npSort->ulMaxKey=%ld, pSort->ulPages=%ld, pSort->ulPgKeys=%ld, size=%ld\r\n", + pSort->ulMaxKey, pSort->ulPages, pSort->ulPgKeys, + pSort->ulMaxKey * ( pSort->keyLen + 4 ) ); fflush(stdout); + */ + if ( pSort->ulPages > 1 ) + { + BYTE * pBuf = pSort->pKeyPool; + hb_cdxSortWritePage( pSort ); + for ( ulPage = 0; ulPage < pSort->ulPages; ulPage++ ) + { + pSort->pSwapPage[ ulPage ].ulKeyBuf = 0; + pSort->pSwapPage[ ulPage ].ulCurKey = 0; + pSort->pSwapPage[ ulPage ].pKeyPool = pBuf; + pBuf += pSort->ulPgKeys * ( pSort->keyLen + 4 ); + } + } + else + { + hb_cdxSortSortPage( pSort ); + pSort->pSwapPage[ 0 ].ulKeys = pSort->ulKeys; + pSort->pSwapPage[ 0 ].ulKeyBuf = pSort->ulKeys; + pSort->pSwapPage[ 0 ].ulCurKey = 0; + pSort->pSwapPage[ 0 ].pKeyPool = pSort->pKeyPool; + } + +#ifdef HB_CDX_NEW_SORT + hb_cdxSortOrderPages( pSort ); +#endif + + for ( ulKey = 0; ulKey < pSort->ulTotKeys; ulKey++ ) + { + if ( ! hb_cdxSortKeyGet( pSort, &pKeyVal, &ulRec ) ) + { + hb_errInternal( 9999, "hb_cdxSortOut: memory structure corrupted.", "", "" ); + } + if ( fUnique ) + { + if ( ulKey != 0 && hb_cdxValCompare( pSort->pTag, pSort->pLastKey, iLen, pKeyVal, iLen, TRUE ) == 0 ) + { + continue; + } + } +#ifdef HB_CDX_DBGCODE_EXT + if ( ulKey != 0 ) + { + int i = hb_cdxValCompare( pSort->pTag, pSort->pLastKey, iLen, pKeyVal, iLen, TRUE ); + if ( i == 0 ) + { + i = ( pSort->ulLastRec < ulRec ) ? -1 : 1; + } + if ( i > 0 ) + { + printf("\r\nulKey=%ld, pKeyVal=[%s][%ld], pKeyLast=[%s][%ld]\r\n", + ulKey, pKeyVal, ulRec, pSort->pLastKey, pSort->ulLastRec); fflush(stdout); + hb_errInternal( 9999, "hb_cdxSortOut: sorting fails.", "", "" ); + } + } +#endif + hb_cdxSortAddNodeKey( pSort, 0, pKeyVal, ulRec, 0 ); + memcpy( pSort->pLastKey, pKeyVal, iLen ); + pSort->ulLastRec = ulRec; + } + +#ifdef HB_CDX_DBGCODE + if ( hb_cdxSortKeyGet( pSort, &pKeyVal, &ulRec ) ) + { + hb_errInternal( 9999, "hb_cdxSortOut: memory structure corrupted(2).", "", "" ); + } +#endif + + if ( pSort->NodeList[ 0 ] == NULL ) + { + pSort->NodeList[ 0 ] = hb_cdxPageNew( pSort->pTag, NULL, 0 ); + pSort->NodeList[ 0 ]->PageType = CDX_NODE_LEAF; + hb_cdxPageLeafInitSpace( pSort->NodeList[ 0 ] ); + } + + iLevel = 0; + fNext = TRUE; + do + { + if ( iLevel + 1 == CDX_STACKSIZE || pSort->NodeList[ iLevel + 1 ] == NULL ) + { + pSort->NodeList[ iLevel ]->PageType |= CDX_NODE_ROOT; + pSort->pTag->RootBlock = pSort->NodeList[ iLevel ]->Page; + fNext = FALSE; + } + else + { + hb_cdxSortAddNodeKey( pSort, iLevel + 1, pSort->pLastKey, pSort->ulLastRec, pSort->NodeList[ iLevel ]->Page ); + } + hb_cdxPageFree( pSort->NodeList[ iLevel ], TRUE ); + iLevel++; + } + while ( fNext ); +} + +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, BOOL fReindex ) +{ + LPCDXAREA pArea = pTag->pIndex->pArea; + LPCDXSORTINFO pSort; + PHB_ITEM pForItem, pWhileItem = NULL, pEvalItem = NULL, pItem = NULL; + ULONG ulRecCount, ulRecNo = pArea->ulRecNo; + LONG lStep = 0; +#ifndef HB_CDP_SUPPORT_OFF + /* TODO: this hack is not thread safe, hb_cdp_page has to be thread specific */ + PHB_CODEPAGE cdpTmp = hb_cdp_page; + hb_cdp_page = pArea->cdPage; +#endif + + if ( pArea->lpdbOrdCondInfo ) + { + pEvalItem = pArea->lpdbOrdCondInfo->itmCobEval; + pWhileItem = pArea->lpdbOrdCondInfo->itmCobWhile; + lStep = pArea->lpdbOrdCondInfo->lStep; + } + + if( pTag->Custom || ( pTag->OptFlags & CDX_TYPE_STRUCTURE ) ) + { + ulRecCount = 0; + } + else if( SELF_RECCOUNT( ( AREAP ) pArea, &ulRecCount ) != SUCCESS ) + { + return; + } + + pArea->pSort = pSort = hb_cdxSortNew( pTag, ulRecCount ); + pSort->fReindex = fReindex; + +#if defined( HB_SIXCDX ) + if ( ( pTag->OptFlags & CDX_TYPE_STRUCTURE ) == 0 && pEvalItem ) + { + SELF_GOTO( ( AREAP ) pArea, 0 ); + if ( !hb_cdxEvalCond( pArea, pEvalItem, FALSE ) ) + { + hb_cdxSortFree( pSort ); + pArea->pSort = NULL; + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + return; + } + } +#endif + if( ulRecCount == 0 ) + { + hb_cdxTagEmptyIndex( pTag ); + } + else + { + USHORT uiSaveTag = pArea->uiTag; + ULONG ulStartRec = 0, ulNextCount = 0; + BOOL fDirectRead, fUseFilter = FALSE; + BYTE * pSaveRecBuff = pArea->pRecord, cTemp[8]; + int iRecBuff = 0, iRecBufSize = USHRT_MAX / pArea->uiRecordLen, iRec; + + pForItem = pTag->pForItem; + if ( pTag->nField ) + pItem = hb_itemNew( NULL ); + + if ( !pArea->lpdbOrdCondInfo || pArea->lpdbOrdCondInfo->fAll ) + { + pArea->uiTag = 0; + } + else + { + if( pArea->lpdbOrdCondInfo->itmRecID ) + ulStartRec = hb_itemGetNL( pArea->lpdbOrdCondInfo->itmRecID ); + if ( ulStartRec ) + { + ulNextCount = 1; + } + else if ( pArea->lpdbOrdCondInfo->fRest || pArea->lpdbOrdCondInfo->lNextCount > 0 ) + { + if( pArea->lpdbOrdCondInfo->itmStartRecID ) + ulStartRec = hb_itemGetNL( pArea->lpdbOrdCondInfo->itmStartRecID ); + if( !ulStartRec ) + ulStartRec = ulRecNo; + if( pArea->lpdbOrdCondInfo->lNextCount > 0 ) + ulNextCount = pArea->lpdbOrdCondInfo->lNextCount; + } + else if( pArea->lpdbOrdCondInfo->fUseFilter ) + { + fUseFilter = TRUE; + } + else if ( !pArea->lpdbOrdCondInfo->fUseCurrent ) + { + pArea->uiTag = 0; + } + } + fDirectRead = !hb_set.HB_SET_STRICTREAD && /* !pArea->lpdbRelations && */ + ( !pArea->lpdbOrdCondInfo || pArea->lpdbOrdCondInfo->fAll || + ( pArea->uiTag == 0 && !fUseFilter ) ); + + if ( fDirectRead ) + pSort->pRecBuff = (BYTE *) hb_xgrab( pArea->uiRecordLen * iRecBufSize ); + + if ( ulStartRec == 0 && pArea->uiTag == 0 ) + ulStartRec = 1; + + if ( ulStartRec == 0 ) + { + SELF_GOTOP( ( AREAP ) pArea ); + } + else + { + SELF_GOTO( ( AREAP ) pArea, ulStartRec ); + if ( fUseFilter ) + SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); + } + + ulRecNo = pArea->ulRecNo; + + while ( !pArea->fEof ) + { + if ( fDirectRead ) + { + if ( ulRecNo > ulRecCount ) + break; + if ( iRecBuff == 0 || iRecBuff >= iRecBufSize ) + { + if ( ulRecCount - ulRecNo >= ( ULONG ) iRecBufSize ) + iRec = iRecBufSize; + else + iRec = ulRecCount - ulRecNo + 1; + if( ulNextCount > 0 && ulNextCount < ( ULONG ) iRec ) + iRec = ( int ) ulNextCount; + hb_fsSeekLarge( pArea->hDataFile, + ( HB_FOFFSET ) pArea->uiHeaderLen + + ( HB_FOFFSET ) ( ulRecNo - 1 ) * + ( HB_FOFFSET ) pArea->uiRecordLen, FS_SET ); + hb_fsReadLarge( pArea->hDataFile, pSort->pRecBuff, pArea->uiRecordLen * iRec ); + iRecBuff = 0; + } + pArea->pRecord = pSort->pRecBuff + iRecBuff * pArea->uiRecordLen; + pArea->ulRecNo = ulRecNo; + if( SELF_GETREC( ( AREAP ) pArea, NULL ) == FAILURE ) + break; + pArea->fValidBuffer = pArea->fPositioned = TRUE; + pArea->fDeleted = pArea->pRecord[ 0 ] == '*'; + /* Force relational movement in child WorkAreas */ + if( pArea->lpdbRelations ) + if( SELF_SYNCCHILDREN( ( AREAP ) pArea ) == FAILURE ) + break; + iRecBuff++; + } + +#if !defined( HB_SIXCDX ) + if ( pEvalItem ) + { + if ( lStep >= pArea->lpdbOrdCondInfo->lStep ) + { + lStep = 0; + if ( !hb_cdxEvalCond( pArea, pEvalItem, FALSE ) ) + break; + } + ++lStep; + } +#endif + + if ( pWhileItem && !hb_cdxEvalCond( NULL, pWhileItem, FALSE ) ) + break; + + if ( ulRecNo <= ulRecCount && + ( pForItem == NULL || hb_cdxEvalCond( pArea, pForItem, FALSE ) ) ) + { + double d; + + if ( pTag->nField ) + SELF_GETVALUE( ( AREAP ) pArea, pTag->nField, pItem ); + else + pItem = hb_vmEvalBlockOrMacro( pTag->pKeyItem ); + + switch( hb_itemType( pItem ) ) + { + case HB_IT_STRING: + case HB_IT_STRING | HB_IT_MEMO: + hb_cdxSortKeyAdd( pSort, pArea->ulRecNo, + ( BYTE * ) hb_itemGetCPtr( pItem ), + hb_itemGetCLen( pItem ) ); + break; + + case HB_IT_INTEGER: + case HB_IT_LONG: + case HB_IT_DOUBLE: + d = hb_itemGetND( pItem ); + HB_DBL2ORD( &d, &cTemp[0] ); + hb_cdxSortKeyAdd( pSort, pArea->ulRecNo, cTemp, 8 ); + break; + + case HB_IT_DATE: + d = (double) hb_itemGetDL( pItem ); + HB_DBL2ORD( &d, &cTemp[0] ); + hb_cdxSortKeyAdd( pSort, pArea->ulRecNo, cTemp, 8 ); + break; + + case HB_IT_LOGICAL: + cTemp[0] = (BYTE) (hb_itemGetL( pItem ) ? 'T' : 'F'); + hb_cdxSortKeyAdd( pSort, pArea->ulRecNo, cTemp, 1 ); + break; + + default: + if ( hb_vmRequestQuery() ) + { + pEvalItem = NULL; + ulNextCount = 1; + } + else + { + printf( "hb_cdxTagDoIndex: hb_itemType( pItem ) = %i", hb_itemType( pItem ) ); + } + break; + } + } + + if( ulNextCount > 0 ) + { + if( --ulNextCount == 0 ) + break; + } + +#if defined( HB_SIXCDX ) + if ( pEvalItem ) + { + if ( lStep >= pArea->lpdbOrdCondInfo->lStep ) + { + lStep = 0; + if ( !hb_cdxEvalCond( pArea, pEvalItem, FALSE ) ) + break; + } + ++lStep; + } +#endif + + if( fDirectRead ) + ulRecNo++; + else + { + if( SELF_SKIPRAW( ( AREAP ) pArea, 1 ) == FAILURE ) + break; + if( fUseFilter && SELF_SKIPFILTER( ( AREAP ) pArea, 1 ) == FAILURE ) + break; + ulRecNo = pArea->ulRecNo; + } + } + + hb_cdxSortOut( pSort ); + if ( pTag->nField ) + hb_itemRelease( pItem ); + + if ( fDirectRead ) + { + pArea->pRecord = pSaveRecBuff; + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + } + pArea->uiTag = uiSaveTag; + +#if !defined( HB_SIXCDX ) + if ( pEvalItem && lStep ) + { + /* pArea->fEof = TRUE; */ + hb_cdxEvalCond( pArea, pEvalItem, FALSE ); + } +#endif + } + +#if defined( HB_SIXCDX ) + if ( pEvalItem ) + { + SELF_GOTO( ( AREAP ) pArea, 0 ); + pArea->fBof = FALSE; + hb_cdxEvalCond( pArea, pEvalItem, FALSE ); + } +#endif + + hb_cdxSortFree( pSort ); + pArea->pSort = NULL; + +#ifndef HB_CDP_SUPPORT_OFF + hb_cdp_page = cdpTmp; +#endif +} + +#define __PRG_SOURCE__ __FILE__ +#ifdef HB_PCODE_VER + #undef HB_PRG_PCODE_VER + #define HB_PRG_PCODE_VER HB_PCODE_VER +#endif + +HB_FUNC_EXTERN( _DBF ); + +#if defined( HB_SIXCDX ) + +HB_FUNC( SIXCDX ) {;} + +HB_FUNC( SIXCDX_GETFUNCTABLE ) +{ + RDDFUNCS * pTable; + USHORT * uiCount, uiRddId; + + uiCount = ( USHORT * ) hb_itemGetPtr( hb_param( 1, HB_IT_POINTER ) ); + pTable = ( RDDFUNCS * ) hb_itemGetPtr( hb_param( 2, HB_IT_POINTER ) ); + uiRddId = hb_parni( 4 ); + + HB_TRACE(HB_TR_DEBUG, ("SIXCDX_GETFUNCTABLE(%i, %p)", uiCount, pTable)); + + if ( pTable ) + { + ERRCODE errCode; + + if ( uiCount ) + * uiCount = RDDFUNCSCOUNT; + errCode = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBFFPT" ); + if ( errCode != SUCCESS ) + errCode = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBFDBT" ); + if ( errCode != SUCCESS ) + errCode = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBF" ); + hb_retni( errCode ); + if ( errCode == SUCCESS ) + { + /* + * we successfully register our RDD so now we can initialize it + * You may think that this place is RDD init statement, Druzus + */ + s_uiRddId = uiRddId; + } + } + else + hb_retni( FAILURE ); +} + +static void hb_bmdbfcdxRddInit( void * cargo ) +{ + HB_SYMBOL_UNUSED( cargo ); + + if( hb_rddRegister( "DBF", RDT_FULL ) <= 1 ) + { + hb_rddRegister( "DBFFPT", RDT_FULL ); + if( hb_rddRegister( "SIXCDX", RDT_FULL ) <= 1 ) + { + return; + } + } + + hb_errInternal( HB_EI_RDDINVALID, NULL, NULL, NULL ); + + /* not executed, only to force DBF RDD linking */ + HB_FUNC_EXEC( _DBF ); +} + +HB_INIT_SYMBOLS_BEGIN( bmdbfcdx1__InitSymbols ) +{ "SIXCDX", {HB_FS_PUBLIC|HB_FS_LOCAL}, {HB_FUNCNAME( SIXCDX )}, NULL }, +{ "SIXCDX_GETFUNCTABLE", {HB_FS_PUBLIC|HB_FS_LOCAL}, {HB_FUNCNAME( SIXCDX_GETFUNCTABLE )}, NULL } +HB_INIT_SYMBOLS_END( bmdbfcdx1__InitSymbols ) + +#else + +HB_FUNC( BMDBFCDX ) {;} + +HB_FUNC( BMDBFCDX_GETFUNCTABLE ) +{ + RDDFUNCS * pTable; + USHORT * uiCount, uiRddId; + + uiCount = ( USHORT * ) hb_itemGetPtr( hb_param( 1, HB_IT_POINTER ) ); + pTable = ( RDDFUNCS * ) hb_itemGetPtr( hb_param( 2, HB_IT_POINTER ) ); + uiRddId = hb_parni( 4 ); + + HB_TRACE(HB_TR_DEBUG, ("BMDBFCDX_GETFUNCTABLE(%i, %p)", uiCount, pTable)); + + if ( pTable ) + { + ERRCODE errCode; + + if ( uiCount ) + * uiCount = RDDFUNCSCOUNT; + errCode = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBFFPT" ); + if ( errCode != SUCCESS ) + errCode = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBFDBT" ); + if ( errCode != SUCCESS ) + errCode = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBF" ); + if ( errCode == SUCCESS ) + { + /* + * we successfully register our RDD so now we can initialize it + * You may think that this place is RDD init statement, Druzus + */ + s_uiRddId = uiRddId; + } + hb_retni( errCode ); + } + else + hb_retni( FAILURE ); +} + +static void hb_bmdbfcdxRddInit( void * cargo ) +{ + HB_SYMBOL_UNUSED( cargo ); + + if( hb_rddRegister( "DBF", RDT_FULL ) <= 1 ) + { + hb_rddRegister( "DBFFPT", RDT_FULL ); + if( hb_rddRegister( "BMDBFCDX", RDT_FULL ) <= 1 ) + { + return; + } + } + + hb_errInternal( HB_EI_RDDINVALID, NULL, NULL, NULL ); + + /* not executed, only to force DBF RDD linking */ + HB_FUNC_EXEC( _DBF ); +} + +HB_INIT_SYMBOLS_BEGIN( bmdbfcdx1__InitSymbols ) +{ "BMDBFCDX", {HB_FS_PUBLIC|HB_FS_LOCAL}, {HB_FUNCNAME( BMDBFCDX )}, NULL }, +{ "BMDBFCDX_GETFUNCTABLE", {HB_FS_PUBLIC|HB_FS_LOCAL}, {HB_FUNCNAME( BMDBFCDX_GETFUNCTABLE )}, NULL } +HB_INIT_SYMBOLS_END( bmdbfcdx1__InitSymbols ) + +#endif + +HB_CALL_ON_STARTUP_BEGIN( _hb_bmdbfcdx_rdd_init_ ) + hb_vmAtInit( hb_bmdbfcdxRddInit, NULL ); +HB_CALL_ON_STARTUP_END( _hb_bmdbfcdx_rdd_init_ ) + +#if defined(HB_PRAGMA_STARTUP) +# pragma startup bmdbfcdx1__InitSymbols +# pragma startup _hb_bmdbfcdx_rdd_init_ +#elif defined(HB_MSC_STARTUP) +# 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_bmdbfcdx1__InitSymbols = bmdbfcdx1__InitSymbols; + static HB_$INITSYM hb_vm_auto_bmdbfcdx_rdd_init = _hb_bmdbfcdx_rdd_init_; +# pragma data_seg() +#endif diff --git a/harbour/contrib/bmdbfcdx/bmsixcdx1.c b/harbour/contrib/bmdbfcdx/bmsixcdx1.c new file mode 100644 index 0000000000..10d8eb4c27 --- /dev/null +++ b/harbour/contrib/bmdbfcdx/bmsixcdx1.c @@ -0,0 +1,55 @@ +/* + * $Id$ + */ + +/* + * xHarbour Project source code: + * BMSIXCDX RDD + * + * Copyright 2007 Miguel Angel Marchuet Frutos + * 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_SIXCDX + +#include "bmdbfcdx1.c" diff --git a/harbour/contrib/bmdbfcdx/hbrddbmcdx.h b/harbour/contrib/bmdbfcdx/hbrddbmcdx.h new file mode 100644 index 0000000000..304e741e78 --- /dev/null +++ b/harbour/contrib/bmdbfcdx/hbrddbmcdx.h @@ -0,0 +1,669 @@ +/* + * $Id$ + */ + +/* + * BMDBFCDX RDD (ver.2) + * + * Copyright 1999 Bruno Cantero + * Copyright 2003 Przemyslaw Czerpak + * Copyright 2006 Miguel Angel Marchuet + * 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. + * + */ + +#ifndef HB_RDDCDX_H_ +#define HB_RDDCDX_H_ + +#include "hbsetup.h" +#include "hbapirdd.h" +#include "hbdbferr.h" +#define HB_EXTERNAL_RDDDBF_USE +#include "hbrdddbf.h" + +HB_EXTERN_BEGIN + +/* CDX constants and defaults */ +#define CDX_INDEXEXT ".cdx" +#define CDX_MAXKEY 240 +#define CDX_MAXEXP 255 +#define CDX_MAXTAGNAMELEN 10 +#define CDX_PAGELEN 512 +#define CDX_HEADERLEN 1024 +#define CDX_HEADEREXPLEN (CDX_HEADERLEN - 512) +#define CDX_HEADERPAGES ((CDX_HEADERLEN+CDX_PAGELEN-1)/CDX_PAGELEN) +#define CDX_INT_FREESPACE (CDX_PAGELEN-12) /* 500 */ +#define CDX_EXT_FREESPACE (CDX_PAGELEN-24) /* 488 */ +#define CDX_DUMMYNODE 0xFFFFFFFFL + +/* #define CDX_LOCKOFFSET 0x7FFFFFFEL */ +/* #define CDX_LOCKSIZE 1L */ +#define CDX_STACKSIZE 64 +#define CDX_PAGECACHESIZE 8 +#define CDX_NODE_BRANCH 0 +#define CDX_NODE_ROOT 1 +#define CDX_NODE_LEAF 2 +#define CDX_NODE_UNUSED 0xFF +#define CDX_IGNORE_REC_NUM 0x0L +#define CDX_MAX_REC_NUM 0xFFFFFFFFL +#define CDX_BALANCE_LEAFPAGES 3 +#define CDX_BALANCE_INTPAGES 3 + +#define CDX_CURKEY_UNDEF (1<< 0) +#define CDX_CURKEY_REC (1<< 1) +#define CDX_CURKEY_VAL (1<< 2) +#define CDX_CURKEY_INPAGE (1<< 3) +#define CDX_CURKEY_INSTACK (1<< 4) +#define CDX_CURKEY_NOTEXIST (1<< 5) +#define CDX_CURKEY_RAWCNT (1<< 6) +#define CDX_CURKEY_RAWPOS (1<< 7) +#define CDX_CURKEY_LOGCNT (1<< 8) +#define CDX_CURKEY_LOGPOS (1<< 9) + +#define TOP_RECORD 1 +#define BTTM_RECORD 2 +#define PREV_RECORD 3 +#define NEXT_RECORD 4 +#define PRVU_RECORD 6 +#define NXTU_RECORD 5 + +#define NODE_NEWLASTKEY 1 +#define NODE_SPLIT 2 +#define NODE_JOIN 4 +#define NODE_BALANCE 8 +#define NODE_EAT 16 + +#define CURKEY_RAWCNT(pTag) (((pTag)->curKeyState & CDX_CURKEY_RAWCNT) != 0) +#define CURKEY_LOGCNT(pTag) (((pTag)->curKeyState & CDX_CURKEY_LOGCNT) != 0) +#define CURKEY_SETLOGCNT(pTag, lKeyCount) { (pTag)->curKeyState |= CDX_CURKEY_LOGCNT; \ + (pTag)->logKeyCount = (lKeyCount); } + +#define CURKEY_RAWPOS(pTag) ( ((pTag)->curKeyState & CDX_CURKEY_RAWPOS) != 0 && \ + (pTag)->rawKeyRec == (pTag)->CurKey->rec ) +#define CURKEY_SETRAWPOS(pTag) { (pTag)->curKeyState |= CDX_CURKEY_RAWPOS; \ + (pTag)->rawKeyRec = (pTag)->CurKey->rec; } + +#define CURKEY_LOGPOS(pTag) ( ((pTag)->curKeyState & CDX_CURKEY_LOGPOS) != 0 && \ + (pTag)->logKeyRec == (pTag)->pIndex->pArea->ulRecNo ) +#define CURKEY_SETLOGPOS(pTag) { (pTag)->curKeyState |= CDX_CURKEY_LOGPOS; \ + (pTag)->logKeyRec = (pTag)->pIndex->pArea->ulRecNo; } + +/* +#define CURKEY_UNDEF(pTag) (((pTag)->curKeyState & CDX_CURKEY_UNDEF) != 0) +#define CURKEY_NOTEXIST(pTag) (((pTag)->curKeyState & CDX_CURKEY_NOTEXIST) != 0) +#define CURKEY_ISSET(pTag) (((pTag)->curKeyState & (CDX_CURKEY_NOTEXIST | CDX_CURKEY_UNDEF)) == 0) +#define CURKEY_REC(pTag) ((((pTag)->curKeyState & CDX_CURKEY_REC) != 0) ? (pTag)->curKey->rec : 0) +#define CURKEY_VAL(pTag) ((((pTag)->curKeyState & CDX_CURKEY_VAL) != 0) ? (pTag)->curKey->val : NULL) +#define CURKEY_REFRESH(pTag) +*/ + +#define HB_CDXMAXKEY( x ) ((USHORT) ((x) > CDX_MAXKEY ? CDX_MAXKEY : (x))) +#define HB_CDXBITMASK( x ) ((LONG) ((1L<<(x))-1)) + +/* #define FAST_GOCOLD( A ) (((CDXAREAP) (A))->fRecordChanged || ((CDXAREAP) (A))->fCdxAppend ? (SELF_GOCOLD((A))) : SUCCESS) */ +#define FAST_GOCOLD( A ) SELF_GOCOLD(A) + + +#define CDX_TYPE_UNIQUE 0x01 /* unique index */ +#define CDX_TYPE_TEMPORARY 0x02 /* temporary index */ +#define CDX_TYPE_CUSTOM 0x04 /* custom index */ +#define CDX_TYPE_FORFILTER 0x08 /* for expression present */ +#define CDX_TYPE_BITVECTOR 0x10 /* SoftC? */ +#define CDX_TYPE_COMPACT 0x20 /* FoxPro */ +#define CDX_TYPE_COMPOUND 0x40 /* FoxPro */ +#define CDX_TYPE_STRUCTURE 0x80 /* FoxPro */ + +/* + TODO like in SIXCDX: + switch ( indexOpt & ( CDX_TYPE_TEMPORARY | CDX_TYPE_CUSTOM ) ) + case CDX_TYPE_TEMPORARY: + PARTIAL_RYO + case CDX_TYPE_CUSTOM: + PARTIAL_RYO | CHGONLY_RYO + case CDX_TYPE_TEMPORARY | CDX_TYPE_CUSTOM: + PARTIAL_RYO | NOUPDATE_RYO + if index key begin with: + 'SXCHAR(' or 'SXNUM(' or 'SXDATE(' or 'SXLOG(' + then + | TEMPLATE_RYO + + sx_chill() if ( ! NOUPDATE_RYO ) then set ( CHGONLY_RYO | PARTIAL_RYO ) + if ( indexOpt & ( CDX_TYPE_TEMPORARY | CDX_TYPE_CUSTOM ) != + CDX_TYPE_TEMPORARY | CDX_TYPE_CUSTOM ) + { + indexOpt &= ~CDX_TYPE_CUSTOM; + indexOpt |= CDX_TYPE_TEMPORARY + } + + sx_warm() if ( ! NOUPDATE_RYO ) then clear CHGONLY_RYO + if ( indexOpt & ( CDX_TYPE_TEMPORARY | CDX_TYPE_CUSTOM ) != + CDX_TYPE_TEMPORARY | CDX_TYPE_CUSTOM ) + { + indexOpt |= CDX_TYPE_CUSTOM; + indexOpt &= ~CDX_TYPE_TEMPORARY + } + + sx_freeze() set NOUPDATE_RYO + indexOpt |= CDX_TYPE_TEMPORARY | CDX_TYPE_CUSTOM; +*/ + +/* CDX index node strucutres */ +/* Compact Index Header Record */ +typedef struct _CDXTAGHEADER +{ + BYTE rootPtr [ 4 ]; /* offset of the root node */ + BYTE freePtr [ 4 ]; /* offset of list of free pages or -1 */ + BYTE reserved1[ 4 ]; /* Version number ??? */ + BYTE keySize [ 2 ]; /* key length */ + BYTE indexOpt; /* index options see CDX_TYPE_* */ + BYTE indexSig; /* index signature */ + BYTE reserved2[ 484 ]; + BYTE ignoreCase[ 2 ]; /* 1 = ignore case, key converted to upper */ + BYTE ascendFlg[ 2 ]; /* 0 = ascending 1 = descending */ + BYTE forExpPos[ 2 ]; /* offset of filter expression */ + BYTE forExpLen[ 2 ]; /* length of filter expression */ + BYTE keyExpPos[ 2 ]; /* offset of key expression */ + BYTE keyExpLen[ 2 ]; /* length of key expression */ + BYTE keyExpPool[ CDX_HEADEREXPLEN ]; +} CDXTAGHEADER; +typedef CDXTAGHEADER * LPCDXTAGHEADER; + +/* Compact Index Interior Node Record */ +typedef struct _CDXINTNODE +{ + BYTE attr [ 2 ]; /* node type see CDX_NODE_* */ + BYTE nKeys [ 2 ]; /* number of keys */ + BYTE leftPtr [ 4 ]; /* offset of left node or -1 */ + BYTE rightPtr[ 4 ]; /* offset of right node or -1 */ + BYTE keyPool [ CDX_INT_FREESPACE ]; +} CDXINTNODE; +typedef CDXINTNODE * LPCDXINTNODE; +typedef CDXINTNODE CDXNODE; +typedef CDXNODE * LPCDXNODE; + +/* Compact Index Exterior Node Record */ +typedef struct _CDXEXTNODE +{ + BYTE attr [ 2 ]; /* node type see CDX_NODE_* */ + BYTE nKeys [ 2 ]; /* number of keys */ + BYTE leftPtr [ 4 ]; /* offset of left node or -1 */ + BYTE rightPtr[ 4 ]; /* offset of right node or -1 */ + BYTE freeSpc [ 2 ]; /* free space available in a page */ + BYTE recMask [ 4 ]; /* record number mask */ + BYTE dupMask; /* duplicate bytes count mask */ + BYTE trlMask; /* trailing bytes count mask */ + BYTE recBits; /* number of bits for record number */ + BYTE dupBits; /* number of bits for duplicate count */ + BYTE trlBits; /* number of bits for trailing count */ + BYTE keyBytes; /* total number of bytes for recnn/dup/trail info */ + BYTE keyPool [ CDX_EXT_FREESPACE ]; /* rec/dup/trl */ +} CDXEXTNODE; +typedef CDXEXTNODE * LPCDXEXTNODE; + + + +/* CDX internal memory structures */ + +struct _CDXAREA; /* forward declaration */ +struct _CDXINDEX; /* forward declaration */ +struct _CDXTAG; /* forward declaration */ + +typedef struct _CDXKEY +{ + BYTE * val; + BYTE len; + ULONG rec; +} CDXKEY; +typedef CDXKEY * LPCDXKEY; + +typedef struct _CDXPAGE +{ + ULONG Page; + ULONG Left; + ULONG Right; + + BYTE PageType; + SHORT iKeys; + SHORT iCurKey; + + BOOL fChanged; + BYTE bUsed; + + ULONG RNMask; + BYTE ReqByte; + BYTE RNBits; + BYTE DCBits; + BYTE TCBits; + BYTE DCMask; + BYTE TCMask; + BOOL fBufChanged; + union + { + CDXEXTNODE extNode; + CDXINTNODE intNode; + } node; + BYTE bufKeyVal[ CDX_MAXKEY ]; /* buffer for leaf key val or added branch key */ + SHORT bufKeyNum; /* do not change these vars' order */ + SHORT bufKeyPos; /* they have to be just after the node */ + SHORT bufKeyLen; /* and maybe temporary overwriten when adding */ + SHORT iFree; /* new key to interior node record. */ + BYTE * pKeyBuf; /* pointer to uncompressed leaf page key pool */ + /* SHORT iKeyInBuf; */ + + struct _CDXPAGE * Owner; + struct _CDXPAGE * Child; + struct _CDXTAG * TagParent; + struct _CDXPAGE * pPoolPrev; + struct _CDXPAGE * pPoolNext; +} CDXPAGE; +typedef CDXPAGE * LPCDXPAGE; + +typedef struct _CDXSTACK +{ + LPCDXPAGE Page; + SHORT iKey; +} CDXSTACK; +typedef CDXSTACK * LPCDXSTACK; + +typedef struct _CDXLIST +{ + ULONG ulAddr; + BOOL fStat; + struct _CDXLIST * pNext; +} CDXLIST; +typedef CDXLIST * LPCDXLIST; + +typedef struct _CDXTAG +{ + char * szName; /* Name of tag */ + char * KeyExpr; /* a tag key expression as text */ + char * ForExpr; /* a tag for expression as text */ + PHB_ITEM pKeyItem; /* item with a macro pcode for a tag key expression */ + PHB_ITEM pForItem; /* item with a macro pcode for a tag for expression */ + USHORT uiType; /* a type of key expression value */ + USHORT uiLen; /* length of the key expression value */ + USHORT nField; /* Field number for simple (one field) key expersion */ + BYTE bTrail; /* trailing character for shorter key value */ + BYTE OptFlags; /* index options flag */ + BOOL AscendKey; /* ascending/descending order flag */ + BOOL UniqueKey; /* unique order flag */ + BOOL Temporary; /* temporary order flag */ + BOOL Custom; /* custom order flag */ + + BOOL UsrAscend; /* user settable ascending/descending order flag */ + BOOL UsrUnique; /* user settable unique order flag */ + + BOOL TagChanged; + BOOL TagBOF; + BOOL TagEOF; + + BOOL fRePos; + int curKeyState; /* see: CDX_CURKEY_* */ + ULONG rawKeyCount; + ULONG rawKeyPos; + ULONG rawKeyRec; + ULONG logKeyCount; + ULONG logKeyPos; + ULONG logKeyRec; + + ULONG TagBlock; /* a page offset where a tag header is stored */ + ULONG RootBlock; /* a page offset with the root of keys tree */ + USHORT MaxKeys; /* maximum number of keys in Interior node */ + + struct _CDXINDEX * pIndex; /* a parent index info */ + struct _CDXTAG * pNext; /* pointer to next tag in index */ + + /* CDXSTACK PageStack[ CDX_STACKSIZE ]; */ /* stack with page path to current key */ + LPCDXPAGE RootPage; /* pointer to root of keys tree in memory */ + LPCDXKEY CurKey; /* current value of key expression */ + LPCDXKEY HotKey; /* value of hot key expression */ + BOOL HotFor; /* index FOR condition for HotKey */ + + PHB_ITEM topScope; /* Top scope HB_ITEM */ + LPCDXKEY topScopeKey; /* Top scope index key */ + PHB_ITEM bottomScope; /* Bottom scope HB_ITEM */ + LPCDXKEY bottomScopeKey; /* Bottom index key */ + + LPCDXPAGE pagePool; /* page buffer in memory */ +} CDXTAG; +typedef CDXTAG * LPCDXTAG; + +typedef struct _CDXINDEX +{ + char * szFileName; /* Name of index file */ + char * szRealName; /* Real name of index file */ + FHANDLE hFile; /* Index file handle */ + struct _CDXAREA * pArea; /* Parent WorkArea */ + struct _CDXINDEX * pNext; /* The next index in the list */ + LPCDXTAG pCompound; /* Compound tag */ + LPCDXTAG TagList; /* List of tags in index file */ + BOOL fShared; /* Shared file */ + BOOL fReadonly; /* Read only file */ + BOOL fDelete; /* delete on close flag */ + ULONG nextAvail; /* offset to next free page in the end of index file */ + ULONG freePage; /* offset to next free page inside index file */ + LPCDXLIST freeLst; /* list of free pages in index file */ + int lockWrite; /* number of write lock set */ + int lockRead; /* number of read lock set */ + HB_FOFFSET ulLockPos; /* readlock position for CL53 lock scheme */ +#ifdef HB_CDX_DBGCODE + BOOL RdLck; + BOOL WrLck; +#endif + BOOL fChanged; /* changes written to index, need upadte ulVersion */ + ULONG ulVersion; /* network version/update flag */ + BOOL fFlush; /* changes written to index, need upadte ulVersion */ +} CDXINDEX; +typedef CDXINDEX * LPCDXINDEX; + +/* for index creation */ +typedef struct +{ + HB_FOFFSET nOffset; /* offset in temporary file */ + ULONG ulKeys; /* number of keys in page */ + ULONG ulKeyBuf; /* number of keys in memory buffer */ + ULONG ulCurKey; /* current key in memory buffer */ + BYTE * pKeyPool; /* memory buffer */ +} CDXSWAPPAGE; +typedef CDXSWAPPAGE * LPCDXSWAPPAGE; + +typedef struct +{ + LPCDXTAG pTag; /* current Tag */ + FHANDLE hTempFile; /* handle to temporary file */ + char * szTempFileName; /* temporary file name */ + int keyLen; /* key length */ + BYTE bTrl; /* filler char for shorter keys */ + BOOL fUnique; /* TRUE if index is unique */ + BOOL fReindex; /* TRUE if reindexing is in process */ + ULONG ulMaxRec; /* the highest record number */ + ULONG ulTotKeys; /* total number of keys indexed */ + ULONG ulKeys; /* keys in curently created page */ + ULONG ulPages; /* number of pages */ + ULONG ulCurPage; /* current page */ + ULONG ulPgKeys; /* maximum number of key in page memory buffer */ + ULONG ulMaxKey; /* maximum number of keys in single page */ + BYTE * pKeyPool; /* memory buffer for current page then for pages */ + LPCDXSWAPPAGE pSwapPage; /* list of pages */ + LPCDXPAGE NodeList[ CDX_STACKSIZE ]; /* Stack of pages */ + ULONG ulFirst; + ULONG * pSortedPages; + BYTE pLastKey[ CDX_MAXKEY ]; /* last key val */ + ULONG ulLastRec; + BYTE * pRecBuff; +#ifndef HB_CDX_PACKTRAIL + int iLastTrl; /* last key trailing spaces */ +#endif +} CDXSORTINFO; +typedef CDXSORTINFO * LPCDXSORTINFO; + + + +/* + * DBF WORKAREA + * ------------ + * The Workarea Structure of DBFCDX RDD + * + */ + +typedef struct _CDXAREA +{ + struct _RDDFUNCS * lprfsHost; /* Virtual method table for this workarea */ + USHORT uiArea; /* The number assigned to this workarea */ + void * atomAlias; /* Pointer to the alias symbol for this workarea */ + USHORT uiFieldExtent; /* Total number of fields allocated */ + USHORT uiFieldCount; /* Total number of fields used */ + LPFIELD lpFields; /* Pointer to an array of fields */ + void * lpFieldExtents; /* Void ptr for additional field properties */ + PHB_ITEM valResult; /* All purpose result holder */ + BOOL fTop; /* TRUE if "top" */ + BOOL fBottom; /* TRUE if "bottom" */ + BOOL fBof; /* TRUE if "bof" */ + BOOL fEof; /* TRUE if "eof" */ + BOOL fFound; /* TRUE if "found" */ + DBSCOPEINFO dbsi; /* Info regarding last LOCATE */ + DBFILTERINFO dbfi; /* Filter in effect */ + LPDBORDERCONDINFO lpdbOrdCondInfo; + LPDBRELINFO lpdbRelations; /* Parent/Child relationships used */ + USHORT uiParents; /* Number of parents for this area */ + USHORT heap; + USHORT heapSize; + USHORT rddID; + USHORT uiMaxFieldNameLength; + PHB_CODEPAGE cdPage; /* Area's codepage pointer */ + + /* + * DBFS's additions to the workarea structure + * + * Warning: The above section MUST match WORKAREA exactly! Any + * additions to the structure MUST be added below, as in this + * example. + */ + + FHANDLE hDataFile; /* Data file handle */ + FHANDLE hMemoFile; /* Memo file handle */ + char * szDataFileName; /* Name of data file */ + char * szMemoFileName; /* Name of memo file */ + USHORT uiHeaderLen; /* Size of header */ + USHORT uiRecordLen; /* Size of record */ + USHORT uiMemoBlockSize; /* Size of memo block */ + USHORT uiMemoVersion; /* MEMO file version */ + DBFHEADER dbfHeader; /* DBF header buffer */ + BYTE bTableType; /* DBF type */ + BYTE bMemoType; /* MEMO type used in DBF memo fields */ + BYTE bLockType; /* Type of locking shemes */ + BYTE bCryptType; /* Type of used encryption */ + USHORT * pFieldOffset; /* Pointer to field offset array */ + BYTE * pRecord; /* Buffer of record data */ + ULONG ulRecCount; /* Total records */ + ULONG ulRecNo; /* Current record */ + BOOL fAutoInc; /* WorkArea with auto increment fields */ + BOOL fHasMemo; /* WorkArea with Memo fields */ + BOOL fHasTags; /* WorkArea with MDX or CDX index */ + BOOL fDataFlush; /* data was written to DBF and not commited */ + BOOL fMemoFlush; /* data was written to MEMO and not commited */ + BOOL fShared; /* Shared file */ + BOOL fReadonly; /* Read only file */ + BOOL fValidBuffer; /* State of buffer */ + BOOL fPositioned; /* Positioned record */ + BOOL fRecordChanged; /* Record changed */ + BOOL fAppend; /* TRUE if new record is added */ + BOOL fDeleted; /* TRUE if record is deleted */ + BOOL fEncrypted; /* TRUE if record is encrypted */ + BOOL fTableEncrypted; /* TRUE if table is encrypted */ + BOOL fUpdateHeader; /* Update header of file */ + BOOL fFLocked; /* TRUE if file is locked */ + BOOL fHeaderLocked; /* TRUE if DBF header is locked */ + LPDBRELINFO lpdbPendingRel; /* Pointer to parent rel struct */ + ULONG * pLocksPos; /* List of records locked */ + ULONG ulNumLocksPos; /* Number of records locked */ + BYTE * pCryptKey; /* Pointer to encryption key */ + PHB_DYNS pTriggerSym; /* DynSym pointer to trigger function */ + + /* + * CDX's additions to the workarea structure + * + * Warning: The above section MUST match DBFAREA exactly! Any + * additions to the structure MUST be added below, as in this + * example. + */ + + BOOL fCdxAppend; /* Appended record changed */ + LPCDXINDEX lpIndexes; /* Pointer to indexes array */ + USHORT uiTag; /* current tag focus */ + LPCDXSORTINFO pSort; /* Index build structure */ + BYTE * bCdxSortTab; /* Table with storted characters */ + +} CDXAREA; + +typedef CDXAREA * LPCDXAREA; + +#ifndef CDXAREAP +#define CDXAREAP LPCDXAREA +#endif + +// m Bitmap, b Size, r RecNo +#define BM_SetBit(m,b,r) ((r)<=(b))?((m)[((r)-1)>>5] = (m)[((r)-1)>>5] | (1<<(((r)-1)%32))):0 +#define BM_ClrBit(m,b,r) ((r)<=(b))?((m)[((r)-1)>>5] = (m)[((r)-1)>>5] & ~(1<<(((r)-1)%32))):0 +#define BM_GetBit(m,b,r) (((r)<=(b))?(((m)[((r)-1)>>5] & (1<<(((r)-1)%32)))):0) + +typedef struct _BM_FILTER_ { + PHB_ITEM itmCobExpr; /* Block representation of the FILTER expression */ + PHB_ITEM abFilterText; /* String representation of FILTER expression */ + BOOL fFilter; /* flag to indicate that filter is active */ + BOOL fOptimized; /* Is (should be) filter optimized */ + ULONG* rmap; + ULONG Size; +} BM_FILTER; + +typedef BM_FILTER * LPBM_FILTER; + + +/* + * -- DBFCDX METHODS -- + */ + +#define SUPERTABLE ( &cdxSuper ) + +#define hb_cdxBof NULL +#define hb_cdxEof NULL +#define hb_cdxFound NULL +static ERRCODE hb_cdxGoBottom( CDXAREAP pArea ); +#define hb_cdxGoTo NULL +#define hb_cdxGoToId NULL +static ERRCODE hb_cdxGoTop( CDXAREAP pArea ); +static ERRCODE hb_cdxSeek( CDXAREAP pArea, BOOL bSoftSeek, PHB_ITEM pKey, BOOL bFindLast ); +static ERRCODE hb_cdxSkip( CDXAREAP pArea, LONG lToSkip ); +static ERRCODE hb_cdxSkipFilter( CDXAREAP pArea, LONG lUpDown ); +static ERRCODE hb_cdxSkipRaw( CDXAREAP pArea, LONG lToSkip ); +#define hb_cdxAddField NULL +static ERRCODE hb_cdxAppend( CDXAREAP pArea, BOOL bUnLockAll ); +#define hb_cdxCreateFields NULL +static ERRCODE hb_cdxDeleteRec( CDXAREAP pArea ); +#define hb_cdxDeleted NULL +#define hb_cdxFieldCount NULL +#define hb_cdxFieldDisplay NULL +#define hb_cdxFieldInfo NULL +#define hb_cdxFieldName NULL +static ERRCODE hb_cdxFlush( CDXAREAP pArea ); +#define hb_cdxGetRec NULL +#define hb_cdxGetValue NULL +#define hb_cdxGetVarLen NULL +static ERRCODE hb_cdxGoCold( CDXAREAP pArea ); +static ERRCODE hb_cdxGoHot( CDXAREAP pArea ); +static ERRCODE hb_cdxPutRec( CDXAREAP pArea, BYTE * pBuffer ); +#define hb_cdxPutValue NULL +static ERRCODE hb_cdxRecall( CDXAREAP pArea ); +#define hb_cdxRecCount NULL +#define hb_cdxRecInfo NULL +#define hb_cdxRecNo NULL +#define hb_cdxRecId NULL +#define hb_cdxSetFieldExtent NULL +#define hb_cdxAlias NULL +static ERRCODE hb_cdxClose( CDXAREAP pArea ); +#define hb_cdxCreate NULL +#define hb_cdxInfo NULL +#define hb_cdxNewArea NULL +static ERRCODE hb_cdxOpen( CDXAREAP pArea, LPDBOPENINFO pOpenInfo ); +#define hb_cdxRelease NULL +static ERRCODE hb_cdxStructSize( CDXAREAP pArea, USHORT * uiSize ); +#define hb_cdxSysName NULL +#define hb_cdxEval NULL +static ERRCODE hb_cdxPack ( CDXAREAP pArea ); +#define hb_cdxPackRec NULL +#define hb_cdxSort NULL +#define hb_cdxTrans NULL +#define hb_cdxTransRec NULL +static ERRCODE hb_cdxZap ( CDXAREAP pArea ); +#define hb_cdxChildEnd NULL +#define hb_cdxChildStart NULL +#define hb_cdxChildSync NULL +#define hb_cdxSyncChildren NULL +#define hb_cdxClearRel NULL +#define hb_cdxForceRel NULL +#define hb_cdxRelArea NULL +#define hb_cdxRelEval NULL +#define hb_cdxRelText NULL +#define hb_cdxSetRel NULL +static ERRCODE hb_cdxOrderListAdd( CDXAREAP pArea, LPDBORDERINFO pOrderInfo ); +static ERRCODE hb_cdxOrderListClear( CDXAREAP pArea ); +#define hb_cdxOrderListDelete NULL +static ERRCODE hb_cdxOrderListFocus( CDXAREAP pArea, LPDBORDERINFO pOrderInfo ); +static ERRCODE hb_cdxOrderListRebuild( CDXAREAP pArea ); +#define hb_cdxOrderCondition NULL +static ERRCODE hb_cdxOrderCreate( CDXAREAP pArea, LPDBORDERCREATEINFO pOrderInfo ); +static ERRCODE hb_cdxOrderDestroy( CDXAREAP pArea, LPDBORDERINFO pOrderInfo ); +static ERRCODE hb_cdxOrderInfo( CDXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pOrderInfo ); +static ERRCODE hb_cdxClearFilter( CDXAREAP pArea ); +#define hb_cdxClearLocate NULL +#define hb_cdxClearScope NULL +static ERRCODE hb_cdxCountScope( CDXAREAP pArea, void * pPtr, LONG * plRec ); +#define hb_cdxFilterText NULL +#define hb_cdxScopeInfo NULL +static ERRCODE hb_cdxSetFilter( CDXAREAP pArea, LPDBFILTERINFO pFilterInfo ); +#define hb_cdxSetLocate NULL +#define hb_cdxSetScope NULL +#define hb_cdxSkipScope NULL +#define hb_cdxLocate NULL +#define hb_cdxCompile NULL +#define hb_cdxError NULL +#define hb_cdxEvalBlock NULL +#define hb_cdxRawLock NULL +#define hb_cdxLock NULL +#define hb_cdxUnLock NULL +#define hb_cdxCloseMemFile NULL +#define hb_cdxCreateMemFile NULL +#define hb_cdxGetValueFile NULL +#define hb_cdxOpenMemFile NULL +#define hb_cdxPutValueFile NULL +#define hb_cdxReadDBHeader NULL +#define hb_cdxWriteDBHeader NULL +#define hb_cdxInit NULL +#define hb_cdxExit NULL +#define hb_cdxDrop NULL +#define hb_cdxExists NULL +static ERRCODE hb_cdxRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, PHB_ITEM pItem ); +#define hb_cdxWhoCares NULL + +HB_EXTERN_END + +#endif /* HB_RDDCDX_H_ */ diff --git a/harbour/contrib/bmdbfcdx/make_b32.bat b/harbour/contrib/bmdbfcdx/make_b32.bat new file mode 100644 index 0000000000..b741127650 --- /dev/null +++ b/harbour/contrib/bmdbfcdx/make_b32.bat @@ -0,0 +1,35 @@ +@echo off +rem +rem $Id$ +rem + +if "%1" == "clean" goto CLEAN +if "%1" == "CLEAN" goto CLEAN + +:BUILD + + make -fmakefile.bc %1 %2 %3 > make_b32.log + if errorlevel 1 goto BUILD_ERR + +:BUILD_OK + + copy ..\..\lib\b32\bmdbfcdx.lib ..\..\lib\*.* > nul + if exist ..\..\lib\b32\bmdbfcdx.bak del ..\..\lib\b32\bmdbfcdx.bak + copy ..\..\lib\b32\bmsixcdx.lib ..\..\lib\*.* > nul + if exist ..\..\lib\b32\bmsixcdx.bak del ..\..\lib\b32\bmsixcdx.bak + goto EXIT + +:BUILD_ERR + + notepad make_b32.log + goto EXIT + +:CLEAN + if exist ..\..\lib\b32\bmdbfcdx.lib del ..\..\lib\b32\bmdbfcdx.lib + if exist ..\..\lib\b32\bmdbfcdx.bak del ..\..\lib\b32\bmdbfcdx.bak + if exist ..\..\lib\b32\bmsixcdx.lib del ..\..\lib\b32\bmsixcdx.lib + if exist ..\..\lib\b32\bmsixcdx.bak del ..\..\lib\b32\bmsixcdx.bak + + goto EXIT + +:EXIT \ No newline at end of file diff --git a/harbour/contrib/bmdbfcdx/makefile.bc b/harbour/contrib/bmdbfcdx/makefile.bc new file mode 100644 index 0000000000..803a33bb6e --- /dev/null +++ b/harbour/contrib/bmdbfcdx/makefile.bc @@ -0,0 +1,26 @@ +# +# $Id$ +# + +# makefile for Borland C/C++ 32 bits +# Building of bmdbfcdx.lib +# Clipper 5.3 DBFCDX compatible on SET OPTIMiZE ON + +INCLUDE_DIR = ..\..\include + +BIN_DIR = ..\..\bin\b32 +OBJ_DIR = ..\..\obj\b32 +LIB_DIR = ..\..\lib\b32 + +$(LIB_DIR)\bmdbfcdx.lib : \ + $(OBJ_DIR)\bmdbfcdx1.obj \ + $(OBJ_DIR)\bmsixcdx1.obj + +$(OBJ_DIR)\bmdbfcdx1.obj : bmdbfcdx1.c +$(OBJ_DIR)\bmsixcdx1.obj : bmsixcdx1.c + + +.c.obj: + bcc32 $(CLIBFLAGS) $(C_USR) -c -O2 -DWIN32 -I$(INCLUDE_DIR) -o$@ $< + tlib $(LIB_DIR)\bmdbfcdx.lib -+$@,, + diff --git a/harbour/contrib/bmdbfcdx/readme.txt b/harbour/contrib/bmdbfcdx/readme.txt new file mode 100644 index 0000000000..f03ca8fd96 --- /dev/null +++ b/harbour/contrib/bmdbfcdx/readme.txt @@ -0,0 +1,56 @@ + BMDBFCDX RDD: + ---------------------------------------------------------------------------- + + Is a DBFCDX RDD compatible with clipper 5.3, use SET OPTIMIZE ON to make a + static bitmap filters, with SET OPTIMIZE OFF works as harbour DBFCDX. + + Addons: + + BM_DbSeekWild( uKey, [lSoftSeek], [lFindLast], [lNext], [lAll] ) => .T./.F. or aSeekRec when lAll clause + BM_Turbo( lOnOff ) // Is only recomendable to use it on creating FILTERS + BM_DbGetFilterArray() => aFilterRec + BM_DbSetFilterArray( aFilterRec ) + BM_DbSetFilterArrayAdd( aFilterRec ) + BM_DbSetFilterArrayDel( aFilterRec ) + + Respecting command: + + SET OPTIMIZE + Change the setting that determines whether to optimize using the open orders + when processing a filtered database file +------------------------------------------------------------------------------ + Syntax + + SET OPTIMIZE ON | OFF | () + + Arguments + + ON enables optimization. + + OFF disables optimization. + + is a logical expression that must be enclosed in + parentheses. A value of true (.T.) is the same as ON, and a value of + false (.F.) is the same as OFF. + + Note: The initial default of this setting depends on the RDD. + + Description + + For RDDs that support optimization, such as DBFCDX, SET OPTIMIZE + determines whether to optimize filters based on the orders open in the + current work area. If this flag is ON, the RDD will optimize the search + for records that meet the filter condition to the fullest extent + possible, minimizing the need to read the actual data from the database + file. + + If this flag is OFF, the RDD will not optimize. + + Examples + + ¦ The following example enables optimization for the Inventor + database file using the SET OPTIMIZE command: + + USE Inventor NEW VIA "DBFCDX" + SET OPTIMIZE ON +