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

275 lines
8.2 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1995-2000.
//
// File: SeqSer.cxx
//
// Contents: Sequential cursor for serial (unsorted) results.
//
// Classes: CSequentialSerial
//
// History: 05-Jun-95 KyleP Created
// 14-JAN-97 KrishnaN Undefined CI_INETSRV and related changes
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include "seqser.hxx"
#include "rowman.hxx"
// Rowset object Interfaces that support Ole DB error objects
static const IID * apRowsetErrorIFs[] =
{
&IID_IAccessor,
&IID_IColumnsInfo,
&IID_IConvertType,
&IID_IRowset,
&IID_IRowsetInfo,
//&IID_IRowsetWatchRegion,
//&IID_IRowsetAsynch,
&IID_IRowsetQueryStatus,
//&IID_IColumnsRowset,
&IID_IConnectionPointContainer,
&IID_IRowsetIdentity,
//&IID_IRowsetLocate,
//&IID_IRowsetResynch,
//&IID_IRowsetScroll,
//&IID_IRowsetUpdate,
//&IID_ISupportErrorInfo
};
static const ULONG cRowsetErrorIFs = sizeof(apRowsetErrorIFs)/sizeof(apRowsetErrorIFs[0]);
//+---------------------------------------------------------------------------
//
// Member: CSequentialSerial::CSequentialSerial, public
//
// Synopsis: Constructor.
//
// Arguments: [pUnkOuter] -- outer unknown
// [ppMyUnk] -- OUT: on return, filled with pointer to my
// non-delegating IUnknown
// [aChild] -- Child rowset(s)
// [cChild] -- Count of rowsets in [aChild]
// [Props] -- Rowset properties.
// [cCol] -- Number of original columns.
//
// History: 05-Jun-95 KyleP Created.
//
//----------------------------------------------------------------------------
CSequentialSerial::CSequentialSerial( IUnknown * pUnkOuter,
IUnknown ** ppMyUnk,
IRowset ** aChild,
unsigned cChild,
CMRowsetProps const & Props,
unsigned cCol,
CAccessorBag & aAccessors) :
CDistributedRowset( pUnkOuter, ppMyUnk,
aChild, cChild, Props, cCol,
aAccessors, _DBErrorObj ),
#pragma warning(disable : 4355) // 'this' in a constructor
_DBErrorObj(* (IUnknown *) (IRowset *)this, _mutex ),
#pragma warning(default : 4355) // 'this' in a constructor
_iChild( 0 )
{
_DBErrorObj.SetInterfaceArray(cRowsetErrorIFs, apRowsetErrorIFs);
}
//+---------------------------------------------------------------------------
//
// Member: CSequentialSerial::~CSequentialSerial, public
//
// Synopsis: Virtual destructor.
//
// History: 05-Jun-95 KyleP Created.
//
//----------------------------------------------------------------------------
CSequentialSerial::~CSequentialSerial()
{
}
//+---------------------------------------------------------------------------
//
// Member: CSequentialSerial::_GetNextRows, protected
//
// Synopsis: Sequentially fetch rows
//
// Arguments: [hChapter] -- Chapter
// [cRowsToSkip] -- Skip this many rows before beginning.
// [cRows] -- Try to fetch this many rows.
// [pcRowsObtained] -- Actually fetched this many.
// [pphRows] -- Store HROWs here. Allocate memory if
// [pphRows] is zero.
//
// History: 07-Apr-95 KyleP Created.
//
// Notes: Since every child cursor was given the same bindings, this
// method can be resolved by any of the child cursors.
//
// Notes: Need to have Ole DB error handling here because we are translating
// errors.
//
//----------------------------------------------------------------------------
SCODE CSequentialSerial::_GetNextRows( HCHAPTER hChapter,
DBROWOFFSET cRowsToSkip,
DBROWCOUNT cRows,
DBCOUNTITEM * pcRowsObtained,
HROW * * pphRows )
{
_DBErrorObj.ClearErrorInfo();
SCODE sc = S_OK;
Win4Assert( 0 == hChapter && "Chapter support not yet implemented" );
if (!pcRowsObtained || !pphRows)
{
vqDebugOut(( DEB_IERROR, "CSequentialSerial::GetNextRows: Invalid parameter(s).\n" ));
return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowset);
}
*pcRowsObtained = 0;
if (0 == cRows) // nothing to fetch
return S_OK;
TRY
{
//
// Don't support backwards fetch.
//
if ( cRows < 0 || cRowsToSkip < 0 )
{
return _DBErrorObj.PostHResult(DB_E_CANTFETCHBACKWARDS, IID_IRowset);
}
//
// We may have to allocate memory, if the caller didn't.
//
XCoMem<HROW> xmem;
if ( 0 == *pphRows )
{
xmem.Set( (HROW *)CoTaskMemAlloc( (ULONG) ( cRows * sizeof(HROW) ) ) );
*pphRows = xmem.GetPointer();
}
if ( 0 == *pphRows )
{
vqDebugOut(( DEB_ERROR, "CSequentialSerial::GetNextRows: Out of memory.\n" ));
THROW( CException( E_OUTOFMEMORY ) );
}
//
// Fetch from current child.
//
ULONG cTotalRowsObtained = 0;
while ( cTotalRowsObtained < (ULONG)cRows )
{
if ( _iChild >= _cChild )
{
sc = DB_S_ENDOFROWSET;
break;
}
DBCOUNTITEM cRowsObtained;
HROW * pStart = *pphRows + cTotalRowsObtained;
sc = _aChild[_iChild]->GetNextRows( hChapter,
cRowsToSkip,
cRows - cTotalRowsObtained,
&cRowsObtained,
&pStart );
Win4Assert( pStart == *pphRows + cTotalRowsObtained );
cRowsToSkip = 0;
if ( FAILED(sc) )
{
vqDebugOut(( DEB_ERROR, "Error 0x%x calling IRowset::GetNextRows\n", sc ));
//
// If we already have some rows, then we can't 'unfetch' them, so we have
// to mask this error. Presumably it won't be transient and we'll get it
// again later.
//
if ( cTotalRowsObtained > 0 )
{
sc = DB_S_ROWLIMITEXCEEDED;
}
break;
}
//
// Convert HROWs into distributed HROWs.
//
for ( unsigned i = 0; i < cRowsObtained; i++ )
{
(*pphRows)[cTotalRowsObtained] = _RowManager.Add( _iChild, pStart[i] );
cTotalRowsObtained++;
}
//
// May have to move to next child cursor.
//
if ( sc == DB_S_ENDOFROWSET )
{
_iChild++;
}
else if ( 0 == cRowsObtained )
{
Win4Assert( ( DB_S_ROWLIMITEXCEEDED == sc ) ||
( DB_S_STOPLIMITREACHED == sc ) );
break;
}
}
*pcRowsObtained = cTotalRowsObtained;
xmem.Acquire();
}
CATCH( CException, e )
{
sc = e.GetErrorCode();
}
END_CATCH
if (FAILED(sc))
_DBErrorObj.PostHResult(sc, IID_IRowset);
return sc;
} //_GetNextRows
//+---------------------------------------------------------------------------
//
// Member: CSequentialSerial::RestartPosition, public
//
// Synopsis: Reset cursor for GetNextRows
//
// Arguments: [hChapter] -- Chapter
//
// History: 22 Sep 98 VikasMan Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CSequentialSerial::RestartPosition( HCHAPTER hChapter )
{
_iChild = 0;
return CDistributedRowset::RestartPosition( hChapter );
}