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

516 lines
16 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1995 - 1998.
//
// File: DisAcc.cxx
//
// Contents: Distributed accessor class
//
// Classes: CDistributedAccessor
//
// History: 05-Jun-95 KyleP Created
// 14-JAN-97 KrishnaN Undefined CI_INETSRV and related changes
//
// Notes: See DisBmk.hxx for a description of distriubted bookmark
// format.
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include "disacc.hxx"
#include "bmkacc.hxx"
//+---------------------------------------------------------------------------
//
// Member: CDistributedAccessor::CDistributedAccessor, public
//
// Synopsis: Builds bindings to fetch bookmark.
//
// Arguments: [aCursor] -- Child rowsets.
// [cCursor] -- Count of [aCursor].
// [dwAccessorFlags] -- Binding type.
// [cBindings] -- Count of bindings in [rgBindings].
// [rgBindings] -- Bindings. One per bound column.
// [rgStatus] -- Status reported here. May be null.
// [iBookmark] -- Ordinal of bookmark column.
// [cbBookmark] -- Size of bookmark.
// [pCreator] -- IRowset pointer of creator
// [rgAllBindings] -- rgBindings does not contain the bookmark bindings.
// This param contains all the bindings.
// [cAllBindings] -- Count of all bindings
//
// History: 05-Jun-95 KyleP Created.
//
//----------------------------------------------------------------------------
CDistributedAccessor::CDistributedAccessor( IRowset ** const aCursor,
unsigned cCursor,
DBACCESSORFLAGS dwAccessorFlags,
DBCOUNTITEM cBindings,
DBBINDING const * rgBindings,
DBLENGTH cbRowWidth,
DBBINDSTATUS rgStatus[],
void * pCreator,
DBBINDING const * rgAllBindings,
DBCOUNTITEM cAllBindings )
:
CAccessorBase(pCreator, CAccessorBase::eRowDataAccessor),
_aCursor( aCursor ),
_cCursor( cCursor ),
_aIacc( 0 ),
_ahaccBase( 0 ),
_pDistBmkAcc( 0 ),
_cBookmark( 0 ),
_cBookmarkOffsets( 0 ),
_cAllBindings( 0 ),
_dwAccessorFlags( dwAccessorFlags )
{
SCODE sc = S_OK;
SCODE scLast = S_OK;
unsigned cChildIacc = 0;
unsigned iChildBase = 0;
unsigned iChildBookmark = 0;
// make a copy of all the bindings
Win4Assert( rgAllBindings && cAllBindings > 0 );
_cAllBindings = cAllBindings;
_xAllBindings.Init( (ULONG) _cAllBindings );
RtlCopyMemory( _xAllBindings.GetPointer(),
rgAllBindings,
sizeof( DBBINDING ) * _cAllBindings );
// Copy DBOBJECTs
for ( unsigned iBinding = 0; iBinding < _cAllBindings; iBinding++ )
{
if ( 0 != rgAllBindings[iBinding].pTypeInfo ||
0 != rgAllBindings[iBinding].pBindExt )
{
// These should be NULL as per OLE DB 2.0
if ( rgStatus )
{
rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
}
scLast = DB_E_ERRORSOCCURRED;
}
if ( rgAllBindings[iBinding].pObject )
{
_xAllBindings[iBinding].pObject = new DBOBJECT;
RtlCopyMemory( _xAllBindings[iBinding].pObject,
rgAllBindings[iBinding].pObject,
sizeof( DBOBJECT ) );
}
}
if ( 0 == cBindings )
{
if (FAILED(scLast))
THROW( CException(scLast) );
// 0 bindings - can occur if the bindings only had a bookmark column
return;
}
XArray<DBBINDSTATUS> rgStatTmp( (unsigned) cBindings );
TRY
{
//
// Get accessors from child cursors. All column requests except bookmark
// can be satisfied by a single child cursor. Note that we actually fetch
// the child bookmark here, since it may be a binding(s). We just throw
// that bookmark away. It would be too much trouble to find it later.
//
_ahaccBase = new HACCESSOR [ _cCursor ];
_aIacc = new IAccessor* [ _cCursor ];
RtlZeroMemory(_aIacc, sizeof (IAccessor*) * _cCursor);
for ( ; iChildBase < _cCursor; iChildBase++ )
{
sc = _aCursor[iChildBase]->QueryInterface( IID_IAccessor,
(void **)&_aIacc[iChildBase] );
if (SUCCEEDED( sc ))
{
cChildIacc++;
sc = _aIacc[iChildBase]->CreateAccessor( dwAccessorFlags,
cBindings,
rgBindings,
cbRowWidth,
&_ahaccBase[iChildBase],
rgStatTmp.GetPointer());
if (sc == DB_S_ERRORSOCCURRED && rgStatus)
for (ULONG i = 0; i < cBindings; i++)
if (rgStatTmp[i] != DBBINDSTATUS_OK)
rgStatus[i] = rgStatTmp[i];
}
if ( FAILED(sc) )
{
scLast = sc;
vqDebugOut(( DEB_ERROR,
"CDistributedAccessor: CreateAccessor(child %d) returned 0x%x\n",
iChildBase, sc ));
// Don't throw here. We want to continue on and catch all possible errors
continue;
}
}
if (FAILED(scLast))
THROW( CException(scLast) );
}
CATCH( CException, e )
{
//
// Cleanup as best we can on failure.
//
for ( ; iChildBase > 0; iChildBase-- )
{
_aIacc[iChildBase-1]->ReleaseAccessor( _ahaccBase[iChildBase-1], 0 );
}
for ( ; cChildIacc > 0; cChildIacc-- )
{
_aIacc[cChildIacc-1]->Release();
}
delete [] _aIacc;
_aIacc = 0;
delete [] _ahaccBase;
_ahaccBase = 0;
RETHROW();
}
END_CATCH
Win4Assert( SUCCEEDED(sc) );
}
void CDistributedAccessor::SetupBookmarkAccessor(
CDistributedBookmarkAccessor * pDistBmkAcc,
DBBINDSTATUS rgStatus[],
DBORDINAL iBookmark,
DBBKMARK cBookmark )
{
_cBookmark = cBookmark;
//
// Look for bookmark binding(s)
//
for ( unsigned i = 0; i < _cAllBindings; i++ )
{
if ( _xAllBindings[i].iOrdinal == iBookmark )
{
if ( ( _xAllBindings[i].wType & ~DBTYPE_BYREF) != DBTYPE_BYTES )
{
if ( rgStatus )
rgStatus[i] = DBBINDSTATUS_UNSUPPORTEDCONVERSION;
continue;
}
_xBookmarkOffsets.ReSize( _cBookmarkOffsets + 1 );
_xBookmarkOffsets[_cBookmarkOffsets] = &_xAllBindings[i];
_cBookmarkOffsets++;
}
}
if ( _cBookmarkOffsets )
{
_pDistBmkAcc = pDistBmkAcc;
}
}
//+---------------------------------------------------------------------------
//
// Member: CDistributedAccessor::~CDistributedAccessor, public
//
// Synopsis: Destructor.
//
// History: 05-Jun-95 KyleP Created.
//
//----------------------------------------------------------------------------
CDistributedAccessor::~CDistributedAccessor()
{
// We should have no references left to it
Win4Assert(GetRefcount() == 0);
// Delete DBOBJECTs
for ( unsigned iBinding = 0; iBinding < _cAllBindings; iBinding++ )
{
if ( _xAllBindings[iBinding].pObject )
{
delete _xAllBindings[iBinding].pObject;
}
// These are for future use according to OLE-DB 2.0 and should be NULL
Win4Assert( 0 == _xAllBindings[iBinding].pTypeInfo &&
0 == _xAllBindings[iBinding].pBindExt );
}
delete [] _ahaccBase;
delete [] _aIacc;
CAccessorBase * pParent = GetParent();
if (pParent)
{
if (0 == pParent->DecInheritors() && 0 == pParent->GetRefcount())
{
delete pParent;
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CDistributedAccessor::Release, public
//
// Synopsis: Release all resources (accessors)
//
// Returns: SCODE
//
// History: 05-Jun-95 KyleP Created.
//
// Notes: Even on error, we still try to release as much as possible.
//
//----------------------------------------------------------------------------
ULONG CDistributedAccessor::Release()
{
SCODE sc = S_OK;
if ( 0 == CAccessorBase::Release())
{
if ( 0 != _aIacc )
{
for ( unsigned iChild = 0; iChild < _cCursor; iChild++ )
{
Win4Assert (0 != _aIacc[iChild]);
//
// If this call throws (which it shouldn't accoring to spec)
// we could miss release of some child accessors.
//
SCODE scTemp = _aIacc[iChild]->ReleaseAccessor( _ahaccBase[iChild], 0 );
if ( sc == S_OK )
sc = scTemp;
/*
if ( 0 != _ahaccBookmark )
{
//
// If this call throws (which it shouldn't accoring to spec)
// we could miss release of some child accessors.
//
SCODE scTemp = _aIacc[iChild]->ReleaseAccessor( _ahaccBookmark[iChild], 0 );
if ( sc == S_OK )
sc = scTemp;
}
*/
_aIacc[iChild]->Release();
_aIacc[iChild] = 0;
}
}
}
if (FAILED(sc))
{
THROW( CException(sc) );
}
return( _cRef );
}
//+---------------------------------------------------------------------------
//
// Member: CDistributedAccessor::GetBindings, public
//
// Synopsis: Retrieve a copy of client bindings.
//
// Arguments: [pdwAccessorFlags] -- Bind type returned here.
// [pcBindings] -- Count of bindings in [prgBindings] returned
// here.
// [prgBindings] -- Bindings.
//
// Returns: SCODE
//
// History: 05-Jun-95 KyleP Created.
//
//----------------------------------------------------------------------------
SCODE CDistributedAccessor::GetBindings( DBACCESSORFLAGS * pdwAccessorFlags,
DBCOUNTITEM * pcBindings,
DBBINDING * * prgBindings )
{
Win4Assert( pdwAccessorFlags && pcBindings && prgBindings );
*pcBindings = 0;
*prgBindings = 0;
*pdwAccessorFlags = DBACCESSOR_INVALID;
Win4Assert( _cAllBindings && _xAllBindings.GetPointer() );
*prgBindings = (DBBINDING *) newOLE( sizeof( DBBINDING ) * (ULONG) _cAllBindings );
RtlCopyMemory( *prgBindings,
_xAllBindings.GetPointer(),
sizeof( DBBINDING ) * _cAllBindings );
// Copy DBOBJECTs
for ( unsigned iBinding = 0; iBinding < _cAllBindings; iBinding++ )
{
if ( _xAllBindings[iBinding].pObject )
{
(*prgBindings)[iBinding].pObject = (DBOBJECT*) newOLE( sizeof( DBOBJECT ) );
RtlCopyMemory( (*prgBindings)[iBinding].pObject,
_xAllBindings[iBinding].pObject,
sizeof( DBOBJECT ) );
}
// These are for future use according to OLE-DB 2.0 and should be NULL
Win4Assert( 0 == _xAllBindings[iBinding].pTypeInfo &&
0 == _xAllBindings[iBinding].pBindExt );
}
*pcBindings = _cAllBindings;
*pdwAccessorFlags =_dwAccessorFlags;
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Member: CDistributedAccessor::GetData, public
//
// Synopsis: Fetches data.
//
// Arguments: [iChild] -- Index of child cursor from which base data is
// to be fetched. Indicates 'current' row in [ahrow].
// [hrow] -- HROW for iChild cursor.
// [pData] -- Base for client's data.
//
// Returns: SCODE
//
// History: 05-Jun-95 KyleP Created.
//
// Notes: This optimized version doesn't fetch bookmark(s).
//
//----------------------------------------------------------------------------
SCODE CDistributedAccessor::GetData( unsigned iChild, HROW hrow, void * pData )
{
//
// Fetch base columns
//
return ( _ahaccBase ?
_aCursor[iChild]->GetData( hrow, _ahaccBase[iChild], pData ) :
S_OK );
}
//+---------------------------------------------------------------------------
//
// Member: CDistributedAccessor::GetData, public
//
// Synopsis: Fetches data, including bookmark column.
//
// Arguments: [iChild] -- Index of child cursor from which base data is
// to be fetched. Indicates 'current' row in [ahrow].
// [ahrow] -- 'Top' HROW for all cursors. Used for bookmark
// hints.
// [pData] -- Base for client's data.
//
// Returns: SCODE
//
// History: 05-Jun-95 KyleP Created.
//
//----------------------------------------------------------------------------
SCODE CDistributedAccessor::GetData( unsigned iChild, HROW * ahrow, void * pData )
{
//
// Fetch base columns
//
SCODE sc = GetData( iChild, ahrow[iChild], pData );
//
// If we have bookmark columns, fetch those too.
//
SCODE Status;
XGrowable<BYTE> xBookmarkData;
if ( SUCCEEDED( sc ) && 0 != _pDistBmkAcc )
{
xBookmarkData.SetSize( (unsigned) _cBookmark );
// Fetch bookmark data and value
sc = _pDistBmkAcc->GetData( iChild,
ahrow,
xBookmarkData.Get(),
_cBookmark,
_aCursor,
_cCursor,
&Status );
if ( SUCCEEDED(sc) )
{
// Copy the bookmark data across various bindings
for ( unsigned i = 0; i < _cBookmarkOffsets; i++ )
{
if ( _xBookmarkOffsets[i]->dwPart & DBPART_VALUE )
{
BYTE * pDest;
// is the dest byref
if ( (_xBookmarkOffsets[i]->wType & DBTYPE_BYREF) == DBTYPE_BYREF )
{
pDest = (BYTE*) newOLE( (unsigned) _cBookmark );
*((ULONG_PTR*)((BYTE*)pData + _xBookmarkOffsets[i]->obValue)) =
(ULONG_PTR)pDest;
}
else
{
pDest = (BYTE *)pData + _xBookmarkOffsets[i]->obValue;
}
RtlCopyMemory( pDest, xBookmarkData.Get(), _cBookmark );
}
if ( _xBookmarkOffsets[i]->dwPart & DBPART_LENGTH )
*(DBBKMARK UNALIGNED *)((BYTE *)pData + _xBookmarkOffsets[i]->obLength) = _cBookmark;
if ( _xBookmarkOffsets[i]->dwPart & DBPART_STATUS )
*(DBBKMARK UNALIGNED *)((BYTE *)pData + _xBookmarkOffsets[i]->obStatus) = Status;
}
}
}
return( sc );
}