260 lines
8.7 KiB
C++
260 lines
8.7 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1995 - 2000.
|
||
|
//
|
||
|
// File: RowComp.cxx
|
||
|
//
|
||
|
// Contents: Compares two rows.
|
||
|
//
|
||
|
// Classes: CRowComparator
|
||
|
//
|
||
|
// History: 05-Jun-95 KyleP Created
|
||
|
// 14-JAN-97 KrishnaN Undefined CI_INETSRV and related changes
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include <pch.cxx>
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <compare.hxx>
|
||
|
|
||
|
#include "rowcomp.hxx"
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CRowComparator::CRowComparator, public
|
||
|
//
|
||
|
// Synopsis: Constructor.
|
||
|
//
|
||
|
// History: 05-Jun-95 KyleP Created.
|
||
|
// 02-Feb-2000 KLam Removed END_CONSTRUCTION
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CRowComparator::CRowComparator()
|
||
|
: _aCmp(0),
|
||
|
_aoColumn(0)
|
||
|
{}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CRowComparator::~CRowComparator, public
|
||
|
//
|
||
|
// Synopsis: Destructor.
|
||
|
//
|
||
|
// History: 05-Jun-95 KyleP Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CRowComparator::~CRowComparator()
|
||
|
{
|
||
|
delete [] _aDir;
|
||
|
delete [] _aCmp;
|
||
|
delete [] _aoColumn;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CRowComparator::Init, public
|
||
|
//
|
||
|
// Synopsis: Initializes comparator.
|
||
|
//
|
||
|
// Arguments: [sort] -- Sort specification.
|
||
|
// [aBinding] -- Binding filled in here. Must have one
|
||
|
// element per column in sort.
|
||
|
// [aColumnInfo] -- Column metadata
|
||
|
// [cColumnInfo] -- Size of [aColumnInfo]
|
||
|
//
|
||
|
// Returns: Size of buffer needed to satisfy binding.
|
||
|
//
|
||
|
// History: 05-Jun-95 KyleP Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
unsigned CRowComparator::Init( CSort const & sort,
|
||
|
DBBINDING * aBinding,
|
||
|
DBCOLUMNINFO const * aColumnInfo,
|
||
|
DBORDINAL cColumnInfo )
|
||
|
{
|
||
|
_cColumn = sort.Count();
|
||
|
_aDir = new int [_cColumn];
|
||
|
_aoColumn = new unsigned [_cColumn];
|
||
|
_aCmp = new FDBCmp [_cColumn];
|
||
|
|
||
|
BYTE * pb = (BYTE *)0 + _cColumn * sizeof(CRowComparator::SColumnStatus);
|
||
|
|
||
|
for ( unsigned i = 0; i < _cColumn; i++ )
|
||
|
{
|
||
|
// NTRAID#DB-NTBUG9-84053-2000/07/31-dlee Distributed queries could be faster if ordinals were used to reference columns
|
||
|
|
||
|
for ( DBORDINAL j = 0; j < cColumnInfo; j++ )
|
||
|
{
|
||
|
if ( *(CFullPropSpec *)&aColumnInfo[j].columnid == sort.Get(i).GetProperty() )
|
||
|
{
|
||
|
RtlZeroMemory(&aBinding[i], sizeof (DBBINDING));
|
||
|
aBinding[i].dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
|
||
|
aBinding[i].iOrdinal = aColumnInfo[j].iOrdinal;
|
||
|
aBinding[i].wType = aColumnInfo[j].wType;
|
||
|
// (sizeof (CRowComparator::SColumnStatus) * i ) + offsetof (Status)
|
||
|
aBinding[i].obStatus =
|
||
|
(DBBYTEOFFSET) (ULONG_PTR)&((CRowComparator::SColumnStatus *)0)[i].Status;
|
||
|
// (sizeof (CRowComparator::SColumnStatus) * i ) + offsetof (Length)
|
||
|
aBinding[i].obLength =
|
||
|
(DBBYTEOFFSET) (ULONG_PTR)&((CRowComparator::SColumnStatus *)0)[i].Length;
|
||
|
|
||
|
//
|
||
|
// Invert the meaning of _aCmp[i] for columns that are descending.
|
||
|
//
|
||
|
|
||
|
Win4Assert( QUERY_SORTDESCEND == 1 && QUERY_SORTXDESCEND == 3 );
|
||
|
|
||
|
if ( sort.Get(i).GetOrder() & 1 )
|
||
|
_aDir[i] = -1;
|
||
|
else
|
||
|
_aDir[i] = 1;
|
||
|
|
||
|
_aCmp[i] = VariantCompare.GetDBComparator( (DBTYPEENUM)aColumnInfo[j].wType );
|
||
|
|
||
|
if ( aColumnInfo[j].wType & DBTYPE_VECTOR )
|
||
|
{
|
||
|
_aoColumn[i] = (unsigned)((ULONG_PTR)AlignULONG( pb ));
|
||
|
}
|
||
|
else if ( aColumnInfo[j].wType & DBTYPE_ARRAY )
|
||
|
{
|
||
|
_aoColumn[i] = (unsigned)((ULONG_PTR)AlignULONG( pb ));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
switch ( aColumnInfo[j].wType )
|
||
|
{
|
||
|
case DBTYPE_EMPTY:
|
||
|
case DBTYPE_NULL:
|
||
|
case DBTYPE_STR:
|
||
|
case DBTYPE_BSTR:
|
||
|
case DBTYPE_BYTES:
|
||
|
_aoColumn[i] = (unsigned)((ULONG_PTR)pb);
|
||
|
break;
|
||
|
|
||
|
case DBTYPE_I2:
|
||
|
case DBTYPE_UI2:
|
||
|
case DBTYPE_BOOL:
|
||
|
_aoColumn[i] = (unsigned)((ULONG_PTR)AlignUSHORT( pb ));
|
||
|
break;
|
||
|
|
||
|
case DBTYPE_I4:
|
||
|
case DBTYPE_UI4:
|
||
|
case DBTYPE_ERROR:
|
||
|
_aoColumn[i] = (unsigned)((ULONG_PTR)AlignULONG( pb ));
|
||
|
break;
|
||
|
|
||
|
case DBTYPE_R4:
|
||
|
_aoColumn[i] = (unsigned)((ULONG_PTR)AlignFloat( pb ));
|
||
|
break;
|
||
|
|
||
|
case DBTYPE_R8:
|
||
|
case DBTYPE_DATE:
|
||
|
_aoColumn[i] = (unsigned)((ULONG_PTR)AlignDouble( pb ));
|
||
|
break;
|
||
|
|
||
|
case DBTYPE_CY:
|
||
|
case DBTYPE_I8:
|
||
|
case DBTYPE_UI8:
|
||
|
case DBTYPE_VARIANT:
|
||
|
_aoColumn[i] = (unsigned)((ULONG_PTR)AlignLONGLONG( pb ));
|
||
|
break;
|
||
|
|
||
|
case DBTYPE_GUID:
|
||
|
_aoColumn[i] = (unsigned)((ULONG_PTR)AlignGUID( pb ));
|
||
|
break;
|
||
|
|
||
|
case DBTYPE_WSTR:
|
||
|
_aoColumn[i] = (unsigned)((ULONG_PTR)AlignWCHAR( pb ));
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
vqDebugOut(( DEB_WARN,
|
||
|
"Can't determine alignment for type %d\n",
|
||
|
aColumnInfo[j].wType ));
|
||
|
_aoColumn[i] = (unsigned)((ULONG_PTR)pb);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
aBinding[i].obValue = _aoColumn[i];
|
||
|
aBinding[i].cbMaxLen = aColumnInfo[j].ulColumnSize;
|
||
|
pb = (BYTE *) ULongToPtr( _aoColumn[i] ) + aColumnInfo[j].ulColumnSize;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( j == cColumnInfo )
|
||
|
{
|
||
|
vqDebugOut(( DEB_ERROR, "Can't bind to sort column.\n" ));
|
||
|
Win4Assert( !"Can't bind to sort column." );
|
||
|
THROW( CException(E_FAIL) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
vqDebugOut(( DEB_ITRACE, "CRowComparator: Allocated %d byte buffer for comparisons\n", pb ));
|
||
|
|
||
|
return (unsigned)((ULONG_PTR)pb);
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CRowComparator::IsLT, public
|
||
|
//
|
||
|
// Synopsis: Less-than comparator
|
||
|
//
|
||
|
// Arguments: [pbRow1] -- Data for row 1.
|
||
|
// [cbRow1] -- Size of [pbRow1]
|
||
|
// [IndexRow1] -- Used to break ties.
|
||
|
// [pbRow2] -- Data for row 2.
|
||
|
// [cbRow2] -- Size of [pbRow2]
|
||
|
// [IndexRow2] -- Used to break ties.
|
||
|
//
|
||
|
// Returns: TRUE of row1 < row2.
|
||
|
//
|
||
|
// History: 05-Jun-95 KyleP Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CRowComparator::IsLT( BYTE * pbRow1,
|
||
|
ULONG cbRow1,
|
||
|
int IndexRow1,
|
||
|
BYTE * pbRow2,
|
||
|
ULONG cbRow2,
|
||
|
int IndexRow2 )
|
||
|
{
|
||
|
int iCmp = 0;
|
||
|
|
||
|
CRowComparator::SColumnStatus * aColStatus1 = (CRowComparator::SColumnStatus *)pbRow1;
|
||
|
CRowComparator::SColumnStatus * aColStatus2 = (CRowComparator::SColumnStatus *)pbRow2;
|
||
|
|
||
|
for ( unsigned i = 0; i < _cColumn; i++ )
|
||
|
{
|
||
|
//
|
||
|
// Verify field was successfully retrieved.
|
||
|
//
|
||
|
|
||
|
if ( FAILED(aColStatus1[i].Status) || FAILED(aColStatus2[i].Status) )
|
||
|
break;
|
||
|
|
||
|
iCmp = _aDir[i] * _aCmp[i]( pbRow1 + _aoColumn[i],
|
||
|
(ULONG) aColStatus1[i].Length, // Length will never be 4Gb
|
||
|
pbRow2 + _aoColumn[i],
|
||
|
(ULONG)aColStatus2[i].Length ); // Length will never be 4Gb
|
||
|
|
||
|
if ( 0 != iCmp )
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( 0 == iCmp )
|
||
|
return( IndexRow1 < IndexRow2 );
|
||
|
else
|
||
|
return( iCmp < 0 );
|
||
|
}
|