windows-nt/Source/XPSP1/NT/inetsrv/query/distrib/rowcomp.cxx
2020-09-26 16:20:57 +08:00

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 );
}