//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1994 - 1999. // // File: rowcomp.hxx // // Contents: Declaration of the row comparison classes // // Classes: CRowCompareVariant // // Templates: TRowCompare // // History: 31 Aug 1994 dlee Created // //-------------------------------------------------------------------------- #pragma once #include #include #include #include #include "varntcmp.hxx" #include "pathstor.hxx" class CTableWindow; //+------------------------------------------------------------------------- // // Class: CRowCompare // // Purpose: Abstract class for row comparisons // // Notes: The comparison function should return (for ascending order) // // 1..cSortItems if Row1 > Row2, // 0 if same // -1..-cSortItems if Row1 < Row2 // // Return the opposite for descending order. // // History: 8/24/94 dlee created // //-------------------------------------------------------------------------- class CRowCompare { public: CRowCompare() {} virtual ~CRowCompare() {} virtual int Compare(TBL_OFF oRow1, TBL_OFF oRow2) = 0; }; class CPathStore; //+------------------------------------------------------------------------- // // Class: CRowCompareVariant // // Purpose: Default case of row comparisons if a more optimal // special case is not used. Converts values to variants // and compares the variants. Also used if more than one // (not including WORKID) sort spec specified. // // Notes: This must be declared unwindable because it has embedded // unwindable objects. // //-------------------------------------------------------------------------- class CRowCompareVariant : public CRowCompare { public: CRowCompareVariant(CTableWindow & TableWindow); virtual ~CRowCompareVariant(); int Compare(TBL_OFF oRow1, TBL_OFF oRow2); int CompareObject(CRetriever & obj, TBL_OFF oRow2); enum EVariantSource { eNone, eCompressor, eBuffer, eNewx }; private: void _FreeVariant(CTableColumn * pColumn, CTableVariant * pVar, EVariantSource eSource); void _MakeVariant(CTableColumn * pColumn, BYTE * pbRow, CTableVariant * pVar, EVariantSource & evSource); void _MakeVariant(CTableColumn * pColumn, CRetriever & obj, unsigned iProp); PROPVARIANT * _MakeVariant( unsigned iCol, XUseSharedBuffer & sharedBuf, CRetriever & obj ); void _Cleanup1(); void _Cleanup2(); int _DoCompare(TBL_OFF oRow2); void _InitComparators( CSortSet const & sortSet ); PATHID _GetPathId( const CTableColumn & col, BYTE * pbRow ); BOOL _FastCompare( unsigned iCol, BYTE *pbRow1, BYTE * pbRow2, int & iComp ); BOOL _FastCompare( unsigned iCol, CRetriever & obj, XUseSharedBuffer & sharedBuf, BYTE * pbRow2, int & iComp ); unsigned _cProps; CTableWindow &_TableWindow; // Comparators for the columns XArray _aComparator; // State data for the comparison. XArray _aVar1; XArray _aVar2; XArray _apVar1; XArray _apVar2; XArray _apColumn; XArray _aVarFlags1; XArray _aVarFlags2; // // Used for quick path comparison. // CPathStore * _pPathStore; // // Temporary shared memory for the whole table. // CSharedBuffer & _sharedBuf; // Buffer used for CRetriever temporary data enum { maxcbBuffer = MAX_PATH * sizeof WCHAR }; XBuffer _xBuffer; // Most recent row 1 identified by this member is cached WORKID _widCached; }; //+------------------------------------------------------------------------- // // Template: TRowCompare // // Purpose: Special row comparator for inline values: values that are // stored in the row as opposed to variable-length or easily // compressed data that is stored out-of-line. // // Use of this template is just an optimization over using // CRowCompareVariant, in which data must be converted to a // variant before the comparison (which is slow). // // You can use this template if: // -- only one property is in the sort spec // -- the property value is stored inline // -- the property value datatype supports relational ops // -- length of the value is fixed and is not an array // //-------------------------------------------------------------------------- template class TRowCompare : public CRowCompare { public: TRowCompare( CFixedVarTableWindowAllocator &Alloc, ULONG oData, ULONG dwOrder) : _Alloc( Alloc ), _oData( oData ) { if (0 == (dwOrder & QUERY_SORTDESCEND /*DBSORTORDER_DESCEND*/ )) _iGT = 1; // ascending else _iGT = -1; // descending } ~TRowCompare() {} int Compare( TBL_OFF oRow1, TBL_OFF oRow2 ) { T t1 = * (T *) ((BYTE *) _Alloc.FixedPointer( oRow1 ) + _oData); T t2 = * (T *) ((BYTE *) _Alloc.FixedPointer( oRow2 ) + _oData); if (t1 > t2) return _iGT; if (t1 < t2) return -_iGT; return 0; } private: int _iGT; // return value if 1 > 2 CFixedVarTableWindowAllocator &_Alloc; // allocator where rows are ULONG _oData; // offset in row where value resides }; //+------------------------------------------------------------------------- // // Template: TRowCompareTwo // // Purpose: Same as TRowCompare, except that it also does a second // compare. A is compared first, then B. // // Rules for use of this template are the same as for // TRowCompare // //-------------------------------------------------------------------------- template class TRowCompareTwo : public CRowCompare { public: TRowCompareTwo( CFixedVarTableWindowAllocator &Alloc, ULONG oDataA, ULONG dwOrderA, ULONG oDataB, ULONG dwOrderB ) : _CompareA( Alloc, oDataA, dwOrderA ), _CompareB( Alloc, oDataB, dwOrderB ) {} ~TRowCompareTwo() {} int Compare( TBL_OFF oRow1, TBL_OFF oRow2 ) { int result = _CompareA.Compare( oRow1, oRow2 ); if (0 == result) { // same first key -- now check the second key. // the * 2 means that it was the second column. result = 2 * _CompareB.Compare( oRow1, oRow2 ); } return result; } private: TRowCompare _CompareA; TRowCompare _CompareB; }; //+------------------------------------------------------------------------- // // Template: TRowCompareStringPlus // // Purpose: Same as TRowCompareTwo, except that the first key compared // is a wide string, then the parameterized type is compared. // //-------------------------------------------------------------------------- template class TRowCompareStringPlus : public CRowCompare { public: TRowCompareStringPlus( CFixedVarTableWindowAllocator &Alloc, ULONG oDataString, ULONG dwOrderString, ULONG oDataB, ULONG dwOrderB ) : _Alloc( Alloc ), _oDataString( oDataString ), _CompareB( Alloc, oDataB, dwOrderB ) { if (0 == (dwOrderString & QUERY_SORTDESCEND /*DBSORTORDER_DESCEND*/ )) _iGTString = 1; // ascending else _iGTString = -1; // descending } ~TRowCompareStringPlus() {} int Compare( TBL_OFF oRow1, TBL_OFF oRow2 ) { WCHAR * p1 = * (WCHAR **) ((BYTE *) _Alloc.FixedPointer( oRow1 ) + _oDataString ); WCHAR * p2 = * (WCHAR **) ((BYTE *) _Alloc.FixedPointer( oRow2 ) + _oDataString ); // No string is every guaranteed to exist -- even path, // since a summary catalog may have VT_EMPTY, and a VPATH // is VT_EMPTY for non-web downlevel queries. if ( 0 == p1 ) { if ( 0 == p2 ) return 2 * _CompareB.Compare( oRow1, oRow2 ); else return _iGTString; } else if ( 0 == p2 ) { return -_iGTString; } int rc = CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, p1, -1, p2, -1 ); // rc == 1, means less than // rc == 2, means equal // rc == 3, means greater than int result = rc - 2; if ( result > 0 ) return _iGTString; if ( result < 0 ) return -_iGTString; Win4Assert( 0 == result ); // same first key -- now check the second key. // the * 2 means that it was the second column. return 2 * _CompareB.Compare( oRow1, oRow2 ); } private: int _iGTString; // return value if 1 > 2 CFixedVarTableWindowAllocator &_Alloc; // allocator where rows are ULONG _oDataString; // offset in row where value resides TRowCompare _CompareB; };