diff --git a/ChangeLog.txt b/ChangeLog.txt index b6fa54a97d..4d192c8729 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -10,6 +10,56 @@ * Change, ! Fix, % Optimization, + Addition, - Removal, ; Comment */ +2015-03-20 16:34 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) + * include/Makefile + - include/hbdbsort.h + * src/rdd/Makefile + - src/rdd/hbdbsort.c + * src/rdd/dbf1.c + - completely removed old code used in DBF* RDDs as low level backend + for SORT TO ... command and __dbArrange() function. + It was buggy and extremely inefficient in some cases, i.e. after + 20 hours I killed process which was sorting table with 2'000'000 + records in reverted order so I cannot even say how much time it + needed. + + * src/rdd/dbf1.c + + added new code for table sorting in DBF* RDDs + (SORT TO ... / __dbArrange() backend) + New code fixes many different problems which existed in previous one + like missing support for national collation, wrong descending orders, + wrong sorting of numeric fields with negative values, missing support + for sorting many field types, missing support for transferring MEMO + fields, missing support for transferring records to table with different + field structure or serving by different RDD, etc. + New code is also many times faster then the old one. In practice it + means is now usable for tables with more then few thousands records, + i.e. the test table with 2'000'000 records I used with old code was + copied in sorted order in 13 secs. when pure COPY TO needed 10 secs. + Now it's possible to export sorted tables to different RDDs, i.e. + using DELIM or SDF RDDs in desitnation area. + New code is written in general form without any local to DBF* RDDs + extensions so it can be adopted as base in any other RDD. Probably + I'll move it to default workarea methods so it will be inherited by + all Harbour RDDs and only if necessary authors of some RDDs may + overload it, i.e. to move the operation to the server side in remote + RDDs when source and destination tables are processed by the same + server. + This modification closes the last known for years bug or rather bag + of bugs ;-) in Harbour. + ; NOTE: For large tables new sorting algorithm may access source records + more then once. It means that results may be wrongly sorted when + sorted fields in exported records are modified concurrently by + other station during exporting. This can be easy eliminated by + copping source records to temporary file anyhow it will introduce + additional overhead in all cases and user can easy eliminate the + problem by simple FLOCK before sort or making export to temporary + file and then sorting this file or he can simply ignore this + problem as unimportant in the specific situation so I decided to + not implement double copping. + I haven't tested what Cl*pper exactly does in such case so + I cannot say if current behavior is or isn't Cl*pper compatible. + 2015-03-18 23:16 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * include/hbrddcdx.h * src/rdd/dbfcdx/dbfcdx1.c diff --git a/include/Makefile b/include/Makefile index afaf927afe..cab392dea9 100644 --- a/include/Makefile +++ b/include/Makefile @@ -36,7 +36,6 @@ C_HEADERS := \ hbdate.h \ hbdbf.h \ hbdbferr.h \ - hbdbsort.h \ hbdefs.h \ hberrors.h \ hbexprop.h \ diff --git a/include/hbdbsort.h b/include/hbdbsort.h deleted file mode 100644 index 586e120223..0000000000 --- a/include/hbdbsort.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Harbour Project source code: - * SORT RDD module - * - * Copyright 1999 Bruno Cantero - * www - http://harbour-project.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.txt. 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_DBSORT_H_ -#define HB_DBSORT_H_ - -#include "hbrdddbf.h" - -HB_EXTERN_BEGIN - -/* - * DBQUICKSORT - * ----------- - * The Quick Sort Item Structure - */ - -typedef struct _DBQUICKSORT -{ - PHB_FILE pFile; - char szTempName[ HB_PATH_MAX ]; - HB_BYTE * pBuffer; - HB_BYTE * pSwapBufferA; - HB_BYTE * pSwapBufferB; - HB_BYTE * pCmpBufferA; - HB_BYTE * pCmpBufferB; - HB_USHORT uiRecordLen; - HB_USHORT uiMaxRecords; - LPDBSORTINFO pSortInfo; -} DBQUICKSORT; - -typedef DBQUICKSORT * LPDBQUICKSORT; - -/* - * PROTOTYPES - * ---------- - */ -extern HB_BOOL hb_dbQSortInit( LPDBQUICKSORT pQuickSort, LPDBSORTINFO pSortInfo, HB_USHORT uiRecordLen ); -extern void hb_dbQSortExit( LPDBQUICKSORT pQuickSort ); -extern HB_BOOL hb_dbQSortAdvance( LPDBQUICKSORT pQuickSort, HB_USHORT uiCount ); -extern void hb_dbQSortComplete( LPDBQUICKSORT pQuickSort ); - -HB_EXTERN_END - -#endif /* HB_DBSORT_H_ */ diff --git a/src/rdd/Makefile b/src/rdd/Makefile index 27d303a7d4..99e2fe4dfe 100644 --- a/src/rdd/Makefile +++ b/src/rdd/Makefile @@ -21,7 +21,6 @@ C_SOURCES := \ dbsql.c \ delim1.c \ fieldhb.c \ - hbdbsort.c \ ordcount.c \ ordwldsk.c \ workarea.c \ diff --git a/src/rdd/dbf1.c b/src/rdd/dbf1.c index a15216f385..61b97a95e3 100644 --- a/src/rdd/dbf1.c +++ b/src/rdd/dbf1.c @@ -3,6 +3,7 @@ * DBF RDD module * * Copyright 1999 Bruno Cantero + * Copyright 2003-2015 Przemyslaw Czerpak * www - http://harbour-project.org * * This program is free software; you can redistribute it and/or modify @@ -49,7 +50,6 @@ #define HB_TRIGVAR_BYREF #include "hbrdddbf.h" -#include "hbdbsort.h" #include "hbapiitm.h" #include "hbapistr.h" #include "hbapierr.h" @@ -4843,174 +4843,9 @@ static HB_ERRCODE hb_dbfPack( DBFAREAP pArea ) return SELF_GOTO( &pArea->area, 1 ); } -void hb_dbfTranslateRec( DBFAREAP pArea, HB_BYTE * pBuffer, PHB_CODEPAGE cdp_src, PHB_CODEPAGE cdp_dest ) +static HB_ERRCODE hb_dbfTransCond( DBFAREAP pArea, LPDBTRANSINFO pTransInfo ) { - char * pTmpBuf = NULL; - HB_SIZE nLen; - LPFIELD pField; - HB_USHORT uiIndex; - - for( uiIndex = 0, pField = pArea->area.lpFields; uiIndex < pArea->area.uiFieldCount; uiIndex++, pField++ ) - { - if( ( pField->uiFlags & ( HB_FF_BINARY | HB_FF_UNICODE ) ) == 0 && - ( pField->uiType == HB_FT_STRING || pField->uiType == HB_FT_VARLENGTH ) ) - { - if( pTmpBuf == NULL ) - pTmpBuf = ( char * ) hb_xgrab( pArea->uiRecordLen ); - nLen = pField->uiLen; - hb_cdpnDup2( ( char * ) pBuffer + pArea->pFieldOffset[ uiIndex ], nLen, - pTmpBuf, &nLen, cdp_src, cdp_dest ); - memcpy( pBuffer + pArea->pFieldOffset[ uiIndex ], pTmpBuf, nLen ); - if( pField->uiType == HB_FT_STRING ) - { - if( nLen < ( HB_SIZE ) pField->uiLen ) - memset( pBuffer + pArea->pFieldOffset[ uiIndex ] + nLen, - ' ', pField->uiLen - nLen ); - } - else - { - if( nLen < ( HB_SIZE ) pField->uiLen ) - { - pBuffer[ pArea->pFieldOffset[ uiIndex ] + pField->uiLen - 1 ] = ( HB_BYTE ) nLen; - hb_dbfSetNullFlag( pBuffer, pArea->uiNullOffset, pArea->pFieldBits[ uiIndex ].uiLengthBit ); - } - else - hb_dbfClearNullFlag( pBuffer, pArea->uiNullOffset, pArea->pFieldBits[ uiIndex ].uiLengthBit ); - } - } - } - if( pTmpBuf != NULL ) - hb_xfree( pTmpBuf ); -} - -/* - * Physically reorder a database. - */ -static HB_ERRCODE hb_dbfSort( DBFAREAP pArea, LPDBSORTINFO pSortInfo ) -{ - HB_ULONG ulRecNo; - HB_USHORT uiCount; - HB_BOOL bMoreRecords, bLimited, bValidRecord; - HB_ERRCODE errCode; - DBQUICKSORT dbQuickSort; - HB_BYTE * pBuffer; - - HB_TRACE( HB_TR_DEBUG, ( "hb_dbfSort(%p, %p)", pArea, pSortInfo ) ); - - if( SELF_GOCOLD( &pArea->area ) != HB_SUCCESS ) - return HB_FAILURE; - - if( ! hb_dbQSortInit( &dbQuickSort, pSortInfo, pArea->uiRecordLen ) ) - return HB_FAILURE; - - errCode = HB_SUCCESS; - uiCount = 0; - pBuffer = dbQuickSort.pBuffer; - ulRecNo = 1; - if( pSortInfo->dbtri.dbsci.itmRecID ) - { - errCode = SELF_GOTOID( &pArea->area, pSortInfo->dbtri.dbsci.itmRecID ); - bMoreRecords = bLimited = HB_TRUE; - } - else if( pSortInfo->dbtri.dbsci.lNext ) - { - ulRecNo = hb_itemGetNL( pSortInfo->dbtri.dbsci.lNext ); - bLimited = HB_TRUE; - bMoreRecords = ( ulRecNo > 0 ); - } - else - { - if( ! pSortInfo->dbtri.dbsci.itmCobWhile && - ( ! pSortInfo->dbtri.dbsci.fRest || - ! hb_itemGetLX( pSortInfo->dbtri.dbsci.fRest ) ) ) - errCode = SELF_GOTOP( &pArea->area ); - bMoreRecords = HB_TRUE; - bLimited = HB_FALSE; - } - - while( errCode == HB_SUCCESS && ! pArea->area.fEof && bMoreRecords ) - { - if( pSortInfo->dbtri.dbsci.itmCobWhile ) - { - if( SELF_EVALBLOCK( &pArea->area, pSortInfo->dbtri.dbsci.itmCobWhile ) != HB_SUCCESS ) - { - hb_dbQSortExit( &dbQuickSort ); - return HB_FAILURE; - } - bMoreRecords = hb_itemGetLX( pArea->area.valResult ); - } - - if( bMoreRecords && pSortInfo->dbtri.dbsci.itmCobFor ) - { - if( SELF_EVALBLOCK( &pArea->area, pSortInfo->dbtri.dbsci.itmCobFor ) != HB_SUCCESS ) - { - hb_dbQSortExit( &dbQuickSort ); - return HB_FAILURE; - } - bValidRecord = hb_itemGetLX( pArea->area.valResult ); - } - else - bValidRecord = bMoreRecords; - - if( bValidRecord ) - { - if( uiCount == dbQuickSort.uiMaxRecords ) - { - if( ! hb_dbQSortAdvance( &dbQuickSort, uiCount ) ) - { - hb_dbQSortExit( &dbQuickSort ); - return HB_FAILURE; - } - pBuffer = dbQuickSort.pBuffer; - uiCount = 0; - } - - /* Read record */ - if( ! pArea->fValidBuffer && ! hb_dbfReadRecord( pArea ) ) - { - hb_dbQSortExit( &dbQuickSort ); - return HB_FAILURE; - } - - /* Copy data */ - memcpy( pBuffer, pArea->pRecord, pArea->uiRecordLen ); - - if( pArea->area.cdPage != hb_vmCDP() ) - { - hb_dbfTranslateRec( pArea, pBuffer, pArea->area.cdPage, hb_vmCDP() ); - } - - pBuffer += pArea->uiRecordLen; - uiCount++; - } - - if( bMoreRecords && bLimited ) - bMoreRecords = ( --ulRecNo > 0 ); - if( bMoreRecords ) - errCode = SELF_SKIP( &pArea->area, 1 ); - } - - /* Copy last records */ - if( uiCount > 0 ) - { - if( ! hb_dbQSortAdvance( &dbQuickSort, uiCount ) ) - { - hb_dbQSortExit( &dbQuickSort ); - return HB_FAILURE; - } - } - - /* Sort records */ - hb_dbQSortComplete( &dbQuickSort ); - return HB_SUCCESS; -} - -/* - * Copy one or more records from one WorkArea to another. - */ -static HB_ERRCODE hb_dbfTrans( DBFAREAP pArea, LPDBTRANSINFO pTransInfo ) -{ - HB_TRACE( HB_TR_DEBUG, ( "hb_dbfTrans(%p, %p)", pArea, pTransInfo ) ); + HB_TRACE( HB_TR_DEBUG, ( "hb_dbfTransCond(%p, %p)", pArea, pTransInfo ) ); if( pTransInfo->uiFlags & DBTF_MATCH ) { @@ -5034,7 +4869,671 @@ static HB_ERRCODE hb_dbfTrans( DBFAREAP pArea, LPDBTRANSINFO pTransInfo ) } } - return SUPER_TRANS( &pArea->area, pTransInfo ); + return HB_SUCCESS; +} + +/* NOTE: For large tables the sorting algorithm may access source records + more then once. It means that results may be wrongly sorted when + table is changed online by other station during exporting. This + can be easy eliminated by copping source records to temporary + file anyhow it will introduce additional overhead in all cases + and user can easy eliminate the problem by simple FLOCK before + sort or making export to temporary file and then sorting this + file so I decided to not implement it. + I haven't tested what Cl*pper exactly does in such case so + I cannot say if current behavior is or isn't Cl*pper compatible. + [druzus] + */ +#define HB_SORTREC_ARRAYSIZE 0x10000 +#define HB_SORTREC_FIRSTALLOC 0x100 +#define HB_SORTREC_MINRECBUF 0x10 + +#if HB_SORTREC_ARRAYSIZE <= 0x10000 + typedef HB_U16 HB_SORTIDX; +#else + typedef HB_U32 HB_SORTIDX; +#endif +typedef HB_U32 HB_DBRECNO; + +typedef struct +{ + HB_FOFFSET nOffset; + HB_DBRECNO nCount; + HB_DBRECNO nInBuf; + HB_DBRECNO nCurrent; + HB_DBRECNO * pnRecords; +} +HB_DBSORTPAGE, * PHB_DBSORTPAGE; + +typedef struct +{ + LPDBSORTINFO pSortInfo; + + PHB_FILE pTempFile; + char * szTempFileName; + + HB_SIZE nPages; + HB_SIZE nMaxPage; + PHB_DBSORTPAGE pSwapPages; + + HB_DBRECNO nCount; + HB_DBRECNO nMaxRec; + HB_SORTIDX * pnIndex; + HB_DBRECNO * pnRecords; + HB_DBRECNO * pnOrder; + PHB_ITEM pSortArray; +} +DBSORTREC, * LPDBSORTREC; + +static HB_ERRCODE hb_dbfSortInit( LPDBSORTREC pSortRec, LPDBSORTINFO pSortInfo ) +{ + HB_USHORT uiCount, uiDest; + + HB_TRACE( HB_TR_DEBUG, ( "hb_dbfSortInit(%p, %p)", pSortInfo, pSortRec ) ); + + memset( pSortRec, 0, sizeof( DBSORTREC ) ); + pSortRec->pSortInfo = pSortInfo; + + for( uiCount = uiDest = 0; uiCount < pSortInfo->uiItemCount; ++uiCount ) + { + LPFIELD pField = pSortInfo->dbtri.lpaSource->lpFields + + pSortInfo->lpdbsItem[ uiCount ].uiField - 1; + + switch( pField->uiType ) + { + case HB_FT_ANY: + if( pField->uiLen == 4 ) + { + pSortInfo->lpdbsItem[ uiCount ].uiFlags |= SF_LONG; + break; + } + if( pField->uiLen == 3 ) + break; + case HB_FT_MEMO: + case HB_FT_IMAGE: + case HB_FT_BLOB: + case HB_FT_OLE: + pSortInfo->lpdbsItem[ uiCount ].uiField = 0; + break; + + case HB_FT_INTEGER: + case HB_FT_CURRENCY: + case HB_FT_AUTOINC: + case HB_FT_ROWVER: + pSortInfo->lpdbsItem[ uiCount ].uiFlags |= pField->uiDec == 0 ? + SF_LONG : SF_DOUBLE; + break; + case HB_FT_LONG: + if( pField->uiDec == 0 && pField->uiLen < 19 ) + { + pSortInfo->lpdbsItem[ uiCount ].uiFlags |= SF_LONG; + break; + } + case HB_FT_FLOAT: + case HB_FT_DOUBLE: + case HB_FT_CURDOUBLE: + pSortInfo->lpdbsItem[ uiCount ].uiFlags |= SF_DOUBLE; + break; + + case HB_FT_STRING: + case HB_FT_VARLENGTH: + break; + + case HB_FT_DATE: + case HB_FT_TIME: + case HB_FT_MODTIME: + case HB_FT_TIMESTAMP: + case HB_FT_LOGICAL: + break; + + default: + pSortInfo->lpdbsItem[ uiCount ].uiField = 0; + break; + } + switch( pField->uiType ) + { + case HB_FT_STRING: + case HB_FT_VARLENGTH: + break; + default: + pSortInfo->lpdbsItem[ uiCount ].uiFlags &= ~SF_CASE; + } + if( pSortInfo->lpdbsItem[ uiCount ].uiField != 0 ) + { + if( uiCount != uiDest ) + { + pSortInfo->lpdbsItem[ uiDest ].uiField = pSortInfo->lpdbsItem[ uiCount ].uiField; + pSortInfo->lpdbsItem[ uiDest ].uiFlags = pSortInfo->lpdbsItem[ uiCount ].uiFlags; + } + ++uiDest; + } + } + pSortInfo->uiItemCount = uiDest; + + return HB_SUCCESS; +} + +static void hb_dbfSortFree( LPDBSORTREC pSortRec ) +{ + HB_TRACE( HB_TR_DEBUG, ( "hb_dbfSortFree(%p)", pSortRec ) ); + + if( pSortRec->pTempFile != NULL ) + hb_fileClose( pSortRec->pTempFile ); + if( pSortRec->szTempFileName ) + { + hb_fileDelete( pSortRec->szTempFileName ); + hb_xfree( pSortRec->szTempFileName ); + } + + if( pSortRec->pSortArray ) + hb_itemRelease( pSortRec->pSortArray ); + if( pSortRec->pnIndex ) + hb_xfree( pSortRec->pnIndex ); + if( pSortRec->pnRecords ) + hb_xfree( pSortRec->pnRecords ); + if( pSortRec->pnOrder ) + hb_xfree( pSortRec->pnOrder ); + if( pSortRec->pSwapPages ) + hb_xfree( pSortRec->pSwapPages ); +} + +static int hb_dbfSortCmp( LPDBSORTREC pSortRec, PHB_ITEM pValue1, PHB_ITEM pValue2 ) +{ + HB_USHORT uiCount; + + for( uiCount = 0; uiCount < pSortRec->pSortInfo->uiItemCount; ++uiCount ) + { + HB_USHORT uiFlags = pSortRec->pSortInfo->lpdbsItem[ uiCount ].uiFlags; + PHB_ITEM pItem1 = hb_arrayGetItemPtr( pValue1, uiCount + 1 ); + PHB_ITEM pItem2 = hb_arrayGetItemPtr( pValue2, uiCount + 1 ); + int i = 0; + + if( uiFlags & SF_DOUBLE ) + { + double dValue1 = hb_itemGetND( pItem1 ), + dValue2 = hb_itemGetND( pItem2 ); + i = dValue1 < dValue2 ? -1 : ( dValue1 == dValue2 ? 0 : 1 ); + } + else if( uiFlags & SF_LONG ) + { + HB_MAXINT nValue1 = hb_itemGetNInt( pItem1 ), + nValue2 = hb_itemGetNInt( pItem2 ); + i = nValue1 < nValue2 ? -1 : ( nValue1 == nValue2 ? 0 : 1 ); + } + else if( HB_IS_STRING( pItem1 ) ) + { + if( ! HB_IS_STRING( pItem2 ) ) + i = 1; + else if( uiFlags & SF_CASE ) + i = hb_itemStrICmp( pItem1, pItem2, HB_TRUE ); + else + i = hb_itemStrCmp( pItem1, pItem2, HB_TRUE ); + } + else if( HB_IS_DATETIME( pItem1 ) ) + { + double dValue1 = hb_itemGetTD( pItem1 ), + dValue2 = hb_itemGetTD( pItem2 ); + i = dValue1 < dValue2 ? -1 : ( dValue1 == dValue2 ? 0 : 1 ); + } + else if( HB_IS_LOGICAL( pItem1 ) ) + i = hb_itemGetL( pItem1 ) ? ( hb_itemGetL( pItem2 ) ? 0 : 1 ) : + ( hb_itemGetL( pItem2 ) ? -1 : 0 ); + if( i != 0 ) + return ( uiFlags & SF_DESCEND ) ? -i : i; + } + + return 0; +} + +static int hb_dbfSortCompare( LPDBSORTREC pSortRec, + HB_SORTIDX nIndex1, HB_SORTIDX nIndex2 ) +{ + int i = hb_dbfSortCmp( pSortRec, + hb_arrayGetItemPtr( pSortRec->pSortArray, nIndex1 + 1 ), + hb_arrayGetItemPtr( pSortRec->pSortArray, nIndex2 + 1 ) ); + return i == 0 ? ( nIndex1 < nIndex2 ? -1 : 1 ) : i; +} + +static HB_BOOL hb_dbfSortQSort( LPDBSORTREC pSortRec, HB_SORTIDX * pSrc, + HB_SORTIDX * pBuf, HB_DBRECNO nKeys ) +{ + if( nKeys > 1 ) + { + HB_DBRECNO n1, n2; + HB_SORTIDX * pPtr1, * pPtr2, * pDst; + HB_BOOL f1, f2; + + n1 = nKeys >> 1; + n2 = nKeys - n1; + pPtr1 = &pSrc[ 0 ]; + pPtr2 = &pSrc[ n1 ]; + + f1 = hb_dbfSortQSort( pSortRec, pPtr1, &pBuf[ 0 ], n1 ); + f2 = hb_dbfSortQSort( pSortRec, pPtr2, &pBuf[ n1 ], n2 ); + if( f1 ) + pDst = pBuf; + else + { + pDst = pSrc; + pPtr1 = &pBuf[ 0 ]; + } + if( ! f2 ) + pPtr2 = &pBuf[ n1 ]; + while( n1 > 0 && n2 > 0 ) + { + if( hb_dbfSortCompare( pSortRec, *pPtr1, *pPtr2 ) <= 0 ) + { + *pDst++ = *pPtr1++; + n1--; + } + else + { + *pDst++ = *pPtr2++; + n2--; + } + } + if( n1 > 0 ) + memcpy( pDst, pPtr1, n1 * sizeof( HB_SORTIDX ) ); + else if( n2 > 0 && f1 == f2 ) + memcpy( pDst, pPtr2, n2 * sizeof( HB_SORTIDX ) ); + return ! f1; + } + return HB_TRUE; +} + +static HB_DBRECNO * hb_dbfSortSort( LPDBSORTREC pSortRec ) +{ + HB_SORTIDX * pOrder; + HB_DBRECNO nCount; + + if( pSortRec->pnIndex == NULL ) + pSortRec->pnIndex = ( HB_SORTIDX * ) hb_xgrab( + ( ( HB_SIZE ) pSortRec->nCount << 1 ) * sizeof( HB_SORTIDX ) ); + for( nCount = 0; nCount < pSortRec->nCount; ++nCount ) + pSortRec->pnIndex[ nCount ] = nCount; + + pOrder = pSortRec->pnIndex; + if( ! hb_dbfSortQSort( pSortRec, pOrder, &pSortRec->pnIndex[ pSortRec->nCount ], + pSortRec->nCount ) ) + pOrder += pSortRec->nCount; + + if( pSortRec->pnOrder == NULL ) + pSortRec->pnOrder = ( HB_DBRECNO * ) hb_xgrab( + ( HB_SIZE ) pSortRec->nCount * sizeof( HB_DBRECNO ) ); + for( nCount = 0; nCount < pSortRec->nCount; ++nCount ) + pSortRec->pnOrder[ nCount ] = pSortRec->pnRecords[ pOrder[ nCount ] ]; + + return pSortRec->pnOrder; +} + +static void hb_dbfSortInsPage( LPDBSORTREC pSortRec, HB_SORTIDX * pIndex, + HB_SORTIDX nFirst, HB_SORTIDX nLast, + HB_SORTIDX nAt ) +{ + while( nFirst < nLast ) + { + HB_SORTIDX nMiddle = ( nFirst + nLast ) >> 1; + int i = hb_dbfSortCompare( pSortRec, pIndex[ nAt ], pIndex[ nMiddle ] ); + + if( i < 0 ) + nLast = nMiddle; + else + nFirst = nMiddle + 1; + } + if( nAt == 0 ) + { + if( nFirst > 1 ) + { + nLast = pIndex[ 0 ]; + memmove( pIndex, &pIndex[ 1 ], ( nFirst - 1 ) * sizeof( HB_SORTIDX ) ); + pIndex[ nFirst - 1 ] = nLast; + } + } + else if( nFirst != nAt ) + { + nLast = pIndex[ nAt ]; + memmove( &pIndex[ nFirst + 1 ], &pIndex[ nFirst ], + ( nAt - nFirst ) * sizeof( HB_SORTIDX ) ); + pIndex[ nFirst ] = nLast; + } +} + +static HB_ERRCODE hb_dbfSortWritePage( LPDBSORTREC pSortRec ) +{ + HB_DBRECNO * pData = hb_dbfSortSort( pSortRec ); + HB_SIZE nSize = ( HB_SIZE ) pSortRec->nCount * sizeof( HB_DBRECNO ); + AREAP pArea = pSortRec->pSortInfo->dbtri.lpaSource; + + if( pSortRec->pTempFile == NULL ) + { + char szName[ HB_PATH_MAX ]; + pSortRec->pTempFile = hb_fileCreateTemp( NULL, NULL, FC_NORMAL, szName ); + if( pSortRec->pTempFile == NULL ) + { + hb_dbfErrorRT( ( DBFAREAP ) pArea, EG_CREATE, EDBF_CREATE_TEMP, + szName, hb_fsError(), 0, NULL ); + return HB_FAILURE; + } + pSortRec->szTempFileName = hb_strdup( szName ); + } + + if( pSortRec->nPages == pSortRec->nMaxPage ) + { + pSortRec->nMaxPage += 8; + pSortRec->pSwapPages = ( PHB_DBSORTPAGE ) hb_xrealloc( pSortRec->pSwapPages, + pSortRec->nMaxPage * sizeof( HB_DBSORTPAGE ) ); + } + memset( &pSortRec->pSwapPages[ pSortRec->nPages ], 0, sizeof( HB_DBSORTPAGE ) ); + pSortRec->pSwapPages[ pSortRec->nPages ].nCount = pSortRec->nCount; + pSortRec->pSwapPages[ pSortRec->nPages ].nOffset = hb_fileSize( pSortRec->pTempFile ); + + if( hb_fileWriteAt( pSortRec->pTempFile, pData, nSize, + pSortRec->pSwapPages[ pSortRec->nPages ].nOffset ) != nSize ) + { + hb_dbfErrorRT( ( DBFAREAP ) pArea, EG_WRITE, EDBF_WRITE_TEMP, + pSortRec->szTempFileName, hb_fsError(), 0, NULL ); + return HB_FAILURE; + } + pSortRec->nPages++; + pSortRec->nCount = 0; + + return HB_SUCCESS; +} + +static HB_ERRCODE hb_dbfSortReadRec( LPDBSORTREC pSortRec, PHB_ITEM pValue ) +{ + AREAP pArea = pSortRec->pSortInfo->dbtri.lpaSource; + HB_SHORT uiCount; + + if( HB_IS_NIL( pValue ) ) + hb_arrayNew( pValue, pSortRec->pSortInfo->uiItemCount ); + else + hb_arraySize( pValue, pSortRec->pSortInfo->uiItemCount ); + + for( uiCount = 0; uiCount < pSortRec->pSortInfo->uiItemCount; uiCount++ ) + { + PHB_ITEM pItem = hb_arrayGetItemPtr( pValue, uiCount + 1 ); + HB_USHORT uiField = pSortRec->pSortInfo->lpdbsItem[ uiCount ].uiField; + if( SELF_GETVALUE( pArea, uiField, pItem ) != HB_SUCCESS ) + return HB_FAILURE; + } + + return HB_SUCCESS; +} + +static HB_ERRCODE hb_dbfSortReadPage( LPDBSORTREC pSortRec, PHB_DBSORTPAGE pPage ) +{ + AREAP pArea = pSortRec->pSortInfo->dbtri.lpaSource; + HB_DBRECNO nCount = HB_MIN( pSortRec->nMaxRec, pPage->nCount ); + HB_SIZE nSize = ( HB_SIZE ) nCount * sizeof( HB_DBRECNO ); + + if( hb_fileReadAt( pSortRec->pTempFile, pPage->pnRecords, nSize, + pPage->nOffset ) != nSize ) + { + hb_dbfErrorRT( ( DBFAREAP ) pArea, EG_READ, EDBF_READ_TEMP, + pSortRec->szTempFileName, hb_fsError(), 0, NULL ); + return HB_FAILURE; + } + pPage->nOffset += nSize; + pPage->nInBuf = nCount; + pPage->nCurrent = 0; + + return HB_SUCCESS; +} + +static HB_ERRCODE hb_dbfSortGetRec( LPDBSORTREC pSortRec, HB_DBRECNO * pnRecNo ) +{ + HB_SORTIDX nPage = pSortRec->pnIndex[ 0 ]; + PHB_DBSORTPAGE pPage = &pSortRec->pSwapPages[ nPage ]; + + *pnRecNo = pPage->pnRecords[ pPage->nCurrent++ ]; + if( --pPage->nCount == 0 ) + { + if( --pSortRec->nPages > 0 ) + memmove( pSortRec->pnIndex, &pSortRec->pnIndex[ 1 ], + pSortRec->nPages * sizeof( HB_SORTIDX ) ); + } + else + { + if( pPage->nCurrent == pPage->nInBuf ) + { + if( hb_dbfSortReadPage( pSortRec, pPage ) != HB_SUCCESS ) + return HB_FAILURE; + } + if( pSortRec->nPages > 1 ) + { + AREAP pArea = pSortRec->pSortInfo->dbtri.lpaSource; + if( SELF_GOTO( pArea, pPage->pnRecords[ pPage->nCurrent ] ) != HB_SUCCESS || + hb_dbfSortReadRec( pSortRec, hb_arrayGetItemPtr( pSortRec->pSortArray, + nPage + 1 ) ) != HB_SUCCESS ) + return HB_FAILURE; + hb_dbfSortInsPage( pSortRec, pSortRec->pnIndex, 1, pSortRec->nPages, 0 ); + } + } + + return HB_SUCCESS; +} + +static HB_ERRCODE hb_dbfSortFinish( LPDBSORTREC pSortRec ) +{ + AREAP pArea = pSortRec->pSortInfo->dbtri.lpaSource; + + HB_TRACE( HB_TR_DEBUG, ( "hb_dbfSortFinish(%p)", pSortRec ) ); + + if( pSortRec->nCount > 0 ) + { + if( pSortRec->nPages > 0 ) + { + HB_DBRECNO nCount, * pnOrder; + HB_SORTIDX nPage; + + if( hb_dbfSortWritePage( pSortRec ) != HB_SUCCESS ) + return HB_FAILURE; + + if( pSortRec->pSortArray ) + hb_itemRelease( pSortRec->pSortArray ); + if( pSortRec->pnRecords ) + hb_xfree( pSortRec->pnRecords ); + if( pSortRec->pnIndex ) + hb_xfree( pSortRec->pnIndex ); + if( pSortRec->pnOrder ) + hb_xfree( pSortRec->pnOrder ); + + if( pSortRec->nPages > HB_SORTREC_MINRECBUF ) + pSortRec->nMaxRec = pSortRec->nMaxRec * HB_SORTREC_MINRECBUF / + pSortRec->nPages; + nCount = pSortRec->pSwapPages[ pSortRec->nPages - 1 ].nCount; + if( nCount < pSortRec->nMaxRec ) + nCount = pSortRec->nMaxRec - nCount; + else + nCount = 0; + nCount = pSortRec->nMaxRec * pSortRec->nPages - nCount; + + pSortRec->pSortArray = hb_itemArrayNew( pSortRec->nPages ); + pSortRec->pnRecords = ( HB_DBRECNO * ) hb_xgrab( pSortRec->nPages * + sizeof( HB_DBRECNO ) ); + pSortRec->pnIndex = ( HB_SORTIDX * ) hb_xgrab( pSortRec->nPages * + sizeof( HB_SORTIDX ) ); + pSortRec->pnOrder = pnOrder = ( HB_DBRECNO * ) + hb_xgrab( nCount * sizeof( HB_DBRECNO ) ); + for( nPage = 0; nPage < pSortRec->nPages; ++nPage, pnOrder += pSortRec->nMaxRec ) + { + pSortRec->pSwapPages[ nPage ].pnRecords = pnOrder; + if( hb_dbfSortReadPage( pSortRec, &pSortRec->pSwapPages[ nPage ] ) != HB_SUCCESS || + SELF_GOTO( pArea, pnOrder[ 0 ] ) != HB_SUCCESS || + hb_dbfSortReadRec( pSortRec, hb_arrayGetItemPtr( pSortRec->pSortArray, + nPage + 1 ) ) != HB_SUCCESS ) + return HB_FAILURE; + + pSortRec->pnIndex[ nPage ] = nPage; + if( nPage > 0 ) + hb_dbfSortInsPage( pSortRec, pSortRec->pnIndex, 0, nPage, nPage ); + } + } + else + { + pSortRec->pSwapPages = ( PHB_DBSORTPAGE ) hb_xgrabz( sizeof( HB_DBSORTPAGE ) ); + pSortRec->pSwapPages[ 0 ].nCount = + pSortRec->pSwapPages[ 0 ].nInBuf = pSortRec->nCount; + pSortRec->pSwapPages[ 0 ].pnRecords = hb_dbfSortSort( pSortRec ); + pSortRec->nPages = 1; + pSortRec->pnIndex = ( HB_SORTIDX * ) hb_xrealloc( pSortRec->pnIndex, sizeof( HB_SORTIDX ) ); + if( pSortRec->pSortArray ) + { + hb_itemRelease( pSortRec->pSortArray ); + pSortRec->pSortArray = NULL; + } + if( pSortRec->pnRecords ) + { + hb_xfree( pSortRec->pnRecords ); + pSortRec->pnRecords = NULL; + } + } + } + + while( pSortRec->nPages > 0 ) + { + HB_DBRECNO nRecNo; + + if( hb_dbfSortGetRec( pSortRec, &nRecNo ) != HB_SUCCESS || + SELF_GOTO( pArea, nRecNo ) != HB_SUCCESS || + SELF_TRANSREC( pArea, &pSortRec->pSortInfo->dbtri ) != HB_SUCCESS ) + return HB_FAILURE; + } + + return HB_SUCCESS; +} + +static HB_ERRCODE hb_dbfSortAdd( LPDBSORTREC pSortRec ) +{ + AREAP pArea; + HB_ULONG ulRecNo; + + HB_TRACE( HB_TR_DEBUG, ( "hb_dbfSortAdd(%p)", pSortRec ) ); + + pArea = pSortRec->pSortInfo->dbtri.lpaSource; + + if( pSortRec->nCount == pSortRec->nMaxRec ) + { + if( pSortRec->nMaxRec < HB_SORTREC_ARRAYSIZE ) + { + if( pSortRec->nMaxRec == 0 ) + pSortRec->nMaxRec = HB_SORTREC_FIRSTALLOC; + else + pSortRec->nMaxRec <<= 1; + if( pSortRec->nMaxRec > HB_SORTREC_ARRAYSIZE ) + pSortRec->nMaxRec = HB_SORTREC_ARRAYSIZE; + + pSortRec->pnRecords = ( HB_DBRECNO * ) hb_xrealloc( pSortRec->pnRecords, + ( HB_SIZE ) pSortRec->nMaxRec * sizeof( HB_DBRECNO ) ); + if( pSortRec->pSortArray ) + hb_arraySize( pSortRec->pSortArray, pSortRec->nMaxRec ); + else + pSortRec->pSortArray = hb_itemArrayNew( pSortRec->nMaxRec ); + } + if( pSortRec->nCount == pSortRec->nMaxRec ) + { + if( hb_dbfSortWritePage( pSortRec ) != HB_SUCCESS ) + return HB_FAILURE; + } + } + + if( SELF_RECNO( pArea, &ulRecNo ) != HB_SUCCESS || + hb_dbfSortReadRec( pSortRec, hb_arrayGetItemPtr( pSortRec->pSortArray, + pSortRec->nCount + 1 ) ) != HB_SUCCESS ) + return HB_FAILURE; + pSortRec->pnRecords[ pSortRec->nCount++ ] = ( HB_DBRECNO ) ulRecNo; + + return HB_SUCCESS; +} + +/* + * Export sorted records + */ +static HB_ERRCODE hb_dbfSort( DBFAREAP pArea, LPDBSORTINFO pSortInfo ) +{ + HB_ERRCODE errCode = HB_SUCCESS; + HB_LONG lNext = 1; + HB_BOOL fEof, fFor; + DBSORTREC dbSortRec; + + HB_TRACE( HB_TR_DEBUG, ( "hb_dbfSort(%p, %p)", pArea, pSortInfo ) ); + + if( SELF_GOCOLD( &pArea->area ) != HB_SUCCESS ) + return HB_FAILURE; + + if( hb_dbfSortInit( &dbSortRec, pSortInfo ) != HB_SUCCESS ) + return HB_FAILURE; + + if( pSortInfo->uiItemCount == 0 ) + return SELF_TRANS( &pArea->area, &pSortInfo->dbtri ); + + errCode = hb_dbfTransCond( pArea, &pSortInfo->dbtri ); + if( errCode == HB_SUCCESS ) + { + if( pSortInfo->dbtri.dbsci.itmRecID ) + errCode = SELF_GOTOID( &pArea->area, pSortInfo->dbtri.dbsci.itmRecID ); + else if( pSortInfo->dbtri.dbsci.lNext ) + lNext = hb_itemGetNL( pSortInfo->dbtri.dbsci.lNext ); + else if( ! pSortInfo->dbtri.dbsci.itmCobWhile && + ! hb_itemGetLX( pSortInfo->dbtri.dbsci.fRest ) ) + errCode = SELF_GOTOP( &pArea->area ); + } + + /* TODO: use SKIPSCOPE() method and fRest parameter */ + + while( errCode == HB_SUCCESS && lNext > 0 ) + { + errCode = SELF_EOF( &pArea->area, &fEof ); + if( errCode != HB_SUCCESS || fEof ) + break; + + if( pSortInfo->dbtri.dbsci.itmCobWhile ) + { + errCode = SELF_EVALBLOCK( &pArea->area, pSortInfo->dbtri.dbsci.itmCobWhile ); + if( errCode != HB_SUCCESS || ! hb_itemGetLX( pArea->area.valResult ) ) + break; + } + + if( pSortInfo->dbtri.dbsci.itmCobFor ) + { + errCode = SELF_EVALBLOCK( &pArea->area, pSortInfo->dbtri.dbsci.itmCobFor ); + if( errCode != HB_SUCCESS ) + break; + fFor = hb_itemGetLX( pArea->area.valResult ); + } + else + fFor = HB_TRUE; + + if( fFor ) + errCode = hb_dbfSortAdd( &dbSortRec ); + + if( errCode != HB_SUCCESS || pSortInfo->dbtri.dbsci.itmRecID || + ( pSortInfo->dbtri.dbsci.lNext && --lNext < 1 ) ) + break; + + errCode = SELF_SKIP( &pArea->area, 1 ); + } + + if( errCode == HB_SUCCESS ) + errCode = hb_dbfSortFinish( &dbSortRec ); + + hb_dbfSortFree( &dbSortRec ); + + return errCode; +} + +/* + * Copy one or more records from one WorkArea to another. + */ +static HB_ERRCODE hb_dbfTrans( DBFAREAP pArea, LPDBTRANSINFO pTransInfo ) +{ + HB_TRACE( HB_TR_DEBUG, ( "hb_dbfTrans(%p, %p)", pArea, pTransInfo ) ); + + if( hb_dbfTransCond( pArea, pTransInfo ) != HB_SUCCESS ) + return HB_FAILURE; + else + return SUPER_TRANS( &pArea->area, pTransInfo ); } #define hb_dbfTransRec NULL diff --git a/src/rdd/hbdbsort.c b/src/rdd/hbdbsort.c deleted file mode 100644 index b48eb07e18..0000000000 --- a/src/rdd/hbdbsort.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Harbour Project source code: - * SORT RDD module - * - * Copyright 1999 Bruno Cantero - * www - http://harbour-project.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.txt. 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. - * - */ - -#include "hbdbsort.h" - -HB_BOOL hb_dbQSortInit( LPDBQUICKSORT pQuickSort, LPDBSORTINFO pSortInfo, HB_USHORT uiRecordLen ) -{ - /* Create temp file */ - pQuickSort->pFile = hb_fileCreateTemp( NULL, NULL, FC_NORMAL, pQuickSort->szTempName ); - if( pQuickSort->pFile == NULL ) - return HB_FALSE; - - /* Alloc buffers */ - pQuickSort->uiMaxRecords = USHRT_MAX / uiRecordLen; - pQuickSort->pBuffer = ( HB_BYTE * ) hb_xgrab( pQuickSort->uiMaxRecords * uiRecordLen ); - pQuickSort->pSwapBufferA = ( HB_BYTE * ) hb_xgrab( uiRecordLen ); - pQuickSort->pSwapBufferB = ( HB_BYTE * ) hb_xgrab( uiRecordLen ); - pQuickSort->pCmpBufferA = ( HB_BYTE * ) hb_xgrab( uiRecordLen ); - pQuickSort->pCmpBufferB = ( HB_BYTE * ) hb_xgrab( uiRecordLen ); - - /* Fill structure */ - pQuickSort->uiRecordLen = uiRecordLen; - pQuickSort->pSortInfo = pSortInfo; - return HB_TRUE; -} - -void hb_dbQSortExit( LPDBQUICKSORT pQuickSort ) -{ - /* Close and delete temp file */ - hb_fileClose( pQuickSort->pFile ); - hb_fileDelete( pQuickSort->szTempName ); - - /* Free buffers */ - hb_xfree( pQuickSort->pBuffer ); - hb_xfree( pQuickSort->pSwapBufferA ); - hb_xfree( pQuickSort->pSwapBufferB ); - hb_xfree( pQuickSort->pCmpBufferA ); - hb_xfree( pQuickSort->pCmpBufferB ); -} - -HB_BOOL hb_dbQSortAdvance( LPDBQUICKSORT pQuickSort, HB_USHORT uiCount ) -{ - HB_SIZE nSize; - - /* Write chunk */ - nSize = ( HB_SIZE ) uiCount * pQuickSort->uiRecordLen; - return hb_fileWrite( pQuickSort->pFile, pQuickSort->pBuffer, nSize, -1 ) == nSize; -} - -static HB_BOOL hb_dbQSortIsLess( LPDBQUICKSORT pQuickSort, HB_ULONG ulRecNo1, HB_ULONG ulRecNo2 ) -{ - HB_USHORT uiCount, uiField; - DBFAREAP pArea; - LPFIELD pField; - HB_BOOL bAscending, bIgnoreCase; - int iResult; - - pArea = ( DBFAREAP ) pQuickSort->pSortInfo->dbtri.lpaSource; - - /* Read records */ - hb_fileReadAt( pQuickSort->pFile, pQuickSort->pSwapBufferA, - pQuickSort->uiRecordLen, ( ulRecNo1 - 1 ) * pQuickSort->uiRecordLen ); - hb_fileReadAt( pQuickSort->pFile, pQuickSort->pSwapBufferB, - pQuickSort->uiRecordLen, ( ulRecNo2 - 1 ) * pQuickSort->uiRecordLen ); - - /* Compare fields */ - for( uiCount = 0; uiCount < pQuickSort->pSortInfo->uiItemCount; uiCount++ ) - { - /* Sort flags */ - bIgnoreCase = ( ( pQuickSort->pSortInfo->lpdbsItem[ uiCount ].uiFlags & SF_CASE ) == SF_CASE ); - bAscending = ( ( pQuickSort->pSortInfo->lpdbsItem[ uiCount ].uiFlags & SF_ASCEND ) == SF_ASCEND ); - - uiField = pQuickSort->pSortInfo->lpdbsItem[ uiCount ].uiField - 1; - pField = pArea->area.lpFields + uiField; - if( pField->uiType == HB_IT_MEMO ) - continue; - if( pField->uiType == HB_IT_LOGICAL ) - { - if( pQuickSort->pSwapBufferA[ pArea->pFieldOffset[ uiField ] ] == 'T' || - pQuickSort->pSwapBufferA[ pArea->pFieldOffset[ uiField ] ] == 't' || - pQuickSort->pSwapBufferA[ pArea->pFieldOffset[ uiField ] ] == 'Y' || - pQuickSort->pSwapBufferA[ pArea->pFieldOffset[ uiField ] ] == 'y' ) - * pQuickSort->pCmpBufferA = '1'; - else - * pQuickSort->pCmpBufferA = '0'; - if( pQuickSort->pSwapBufferB[ pArea->pFieldOffset[ uiField ] ] == 'T' || - pQuickSort->pSwapBufferB[ pArea->pFieldOffset[ uiField ] ] == 't' || - pQuickSort->pSwapBufferB[ pArea->pFieldOffset[ uiField ] ] == 'Y' || - pQuickSort->pSwapBufferB[ pArea->pFieldOffset[ uiField ] ] == 'y' ) - * pQuickSort->pCmpBufferB = '1'; - else - * pQuickSort->pCmpBufferB = '0'; - } - else - { - memcpy( pQuickSort->pCmpBufferA, pQuickSort->pSwapBufferA + - pArea->pFieldOffset[ uiField ], pField->uiLen ); - memcpy( pQuickSort->pCmpBufferB, pQuickSort->pSwapBufferB + - pArea->pFieldOffset[ uiField ], pField->uiLen ); - } - pQuickSort->pCmpBufferA[ pField->uiLen ] = 0; - pQuickSort->pCmpBufferB[ pField->uiLen ] = 0; - - /* Compare buffers */ - if( bIgnoreCase ) - iResult = hb_stricmp( ( const char * ) pQuickSort->pCmpBufferA, - ( const char * ) pQuickSort->pCmpBufferB ); - else - iResult = strcmp( ( const char * ) pQuickSort->pCmpBufferA, - ( const char * ) pQuickSort->pCmpBufferB ); - - if( iResult == 0 ) - continue; - else if( bAscending ) - return iResult < 0; - else - return iResult > 0; - } - return HB_FALSE; -} - -static void hb_dbQSortSwap( LPDBQUICKSORT pQuickSort, HB_ULONG ulRecNo1, HB_ULONG ulRecNo2 ) -{ - /* Swap records */ - hb_fileReadAt( pQuickSort->pFile, pQuickSort->pSwapBufferA, - pQuickSort->uiRecordLen, ( ulRecNo1 - 1 ) * pQuickSort->uiRecordLen ); - hb_fileReadAt( pQuickSort->pFile, pQuickSort->pSwapBufferB, - pQuickSort->uiRecordLen, ( ulRecNo2 - 1 ) * pQuickSort->uiRecordLen ); - hb_fileWriteAt( pQuickSort->pFile, pQuickSort->pSwapBufferB, - pQuickSort->uiRecordLen, ( ulRecNo1 - 1 ) * pQuickSort->uiRecordLen ); - hb_fileWriteAt( pQuickSort->pFile, pQuickSort->pSwapBufferA, - pQuickSort->uiRecordLen, ( ulRecNo2 - 1 ) * pQuickSort->uiRecordLen ); -} - -static void hb_dbQSortDo( LPDBQUICKSORT pQuickSort, HB_ULONG ulFirst, HB_ULONG ulLast ) -{ - HB_ULONG ulPivot, ulLeft, ulRight; - - /* Select pivot */ - if( hb_dbQSortIsLess( pQuickSort, ulFirst, ulLast ) ) - ulPivot = ulLast; - else - ulPivot = ulFirst; - - ulLeft = ulFirst; - ulRight = ulLast; - do - { - /* partition into two segments */ - while( ulLeft <= ulLast && hb_dbQSortIsLess( pQuickSort, ulLeft, ulPivot ) ) - ulLeft++; - - while( ulRight >= ulFirst && hb_dbQSortIsLess( pQuickSort, ulPivot, ulRight ) ) - ulRight--; - - if( ulLeft <= ulRight ) - { - /* Swap records */ - if( ulLeft < ulRight ) - hb_dbQSortSwap( pQuickSort, ulLeft, ulRight ); - ulLeft++; - ulRight--; - } - } - while( ulLeft <= ulRight ); - - /* Sort segment */ - if( ulFirst < ulRight ) - hb_dbQSortDo( pQuickSort, ulFirst, ulRight ); - - /* Sort segment */ - if( ulLeft < ulLast ) - hb_dbQSortDo( pQuickSort, ulLeft, ulLast ); -} - -void hb_dbQSortComplete( LPDBQUICKSORT pQuickSort ) -{ - HB_ULONG ulRecCount; - AREAP pArea; - - ulRecCount = ( HB_ULONG ) ( hb_fileSize( pQuickSort->pFile ) / pQuickSort->uiRecordLen ); - if( ulRecCount >= 1 ) - { - hb_dbQSortDo( pQuickSort, 1, ulRecCount ); - pArea = pQuickSort->pSortInfo->dbtri.lpaDest; - hb_fileSeek( pQuickSort->pFile, 0, FS_SET ); - while( ulRecCount-- > 0 ) - { - /* Read sorted record */ - hb_fileRead( pQuickSort->pFile, pQuickSort->pSwapBufferA, pQuickSort->uiRecordLen, -1 ); - - /* Remove deleted flag */ - pQuickSort->pSwapBufferA[ 0 ] = ' '; - - if( pArea->cdPage != hb_vmCDP() ) - { - hb_dbfTranslateRec( ( DBFAREAP ) pArea, ( HB_BYTE * ) pQuickSort->pSwapBufferA, hb_vmCDP(), pArea->cdPage ); - } - - /* Append a new record and copy data */ - if( SELF_APPEND( pArea, HB_TRUE ) == HB_FAILURE || - SELF_PUTREC( pArea, pQuickSort->pSwapBufferA ) == HB_FAILURE ) - break; - } - } - hb_dbQSortExit( pQuickSort ); -}