//+--------------------------------------------------------------------------- // // 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 #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 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 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 ); }