From db16cc886122449fcc506885356dd28f1b11912d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Czerpak?= Date: Fri, 20 Mar 2015 16:34:03 +0100 Subject: [PATCH] 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. --- ChangeLog.txt | 50 +++ include/Makefile | 1 - include/hbdbsort.h | 89 ----- src/rdd/Makefile | 1 - src/rdd/dbf1.c | 837 ++++++++++++++++++++++++++++++++++++--------- src/rdd/hbdbsort.c | 252 -------------- 6 files changed, 718 insertions(+), 512 deletions(-) delete mode 100644 include/hbdbsort.h delete mode 100644 src/rdd/hbdbsort.c 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 ); -}