|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1994 - 2000.
//
// File: rowset.cxx
//
// Contents: OLE DB IRowset implementation for file stores.
// Runs entirely in user space at the client machine.
//
// Classes: CRowset
//
// History: 07 Nov 94 AlanW Created
// 07 May 97 KrishnaN Added Ole-DB error support
//
//--------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <initguid.h> // needed for IServiceProperties
#include <rowset.hxx>
#include <query.hxx>
#include <rownotfy.hxx>
#include <tgrow.hxx>
#include "tabledbg.hxx"
const unsigned MAX_ROW_FETCH = 1000;
inline DBROWSTATUS ScodeToRowstatus( SCODE sc ) { switch (sc) { case S_OK: return DBROWSTATUS_S_OK;
case E_INVALIDARG: case DB_E_BADBOOKMARK: return DBROWSTATUS_E_INVALID;
case E_OUTOFMEMORY: return DBROWSTATUS_E_OUTOFMEMORY;
default: tbDebugOut(( DEB_ERROR, "ScodeToRowStatus: missing conversion for %x\n", sc )); Win4Assert( FAILED( sc ) ); return DBROWSTATUS_E_INVALID; } }
// Rowset object Interfaces that support Ole DB error objects
static const IID * apRowsetErrorIFs[] = { &IID_IAccessor, &IID_IChapteredRowset, &IID_IColumnsInfo, &IID_IColumnsRowset, &IID_IConnectionPointContainer, &IID_IConvertType, &IID_IDBAsynchStatus, &IID_IRowset, //&IID_IRowsetAsynch,
&IID_IRowsetIdentity, &IID_IRowsetInfo, &IID_IRowsetLocate, &IID_IRowsetQueryStatus, //&IID_IRowsetResynch,
&IID_IRowsetScroll, //&IID_IRowsetUpdate,
&IID_IRowsetWatchAll, &IID_IRowsetWatchRegion, //&IID_ISupportErrorInfo,
&IID_IServiceProperties, };
static const ULONG cRowsetErrorIFs = sizeof(apRowsetErrorIFs)/sizeof(apRowsetErrorIFs[0]);
//+---------------------------------------------------------------------------
//
// Member: CRowset::CRowset, public
//
// Synopsis: Creates a locally accessible Table
//
// Arguments: [pUnkOuter] - Outer unknown
// [ppMyUnk] - OUT: filled in with pointer to non-delegated
// IUnknown on return
// [cols] - A reference to the output column set
// [pidmap] - a pid mapper for column IDs and names in cols
// [rQuery] - A reference to an instantiated query
// [rControllingQuery] - OLE controlling unknown (IQuery)
// [fIsCategorized] - TRUE if not the highest-level rowset
// [xProps] - Rowset properties, indicates special semantics,
// such as sequential cursor, use CI for prop
// queries.
// [hCursor] - table cursor handle.
// [aAccessors] -- Bag of accessors which rowsets need to inherit
//
// Notes: Ownership of the output column set may be transferred to
// the table cursor.
//
//----------------------------------------------------------------------------
CRowset::CRowset( IUnknown * pUnkOuter, IUnknown ** ppMyUnk, CColumnSet const & cols, CPidMapperWithNames const & pidmap, PQuery & rQuery, IUnknown & rControllingQuery, BOOL fIsCategorized, XPtr<CMRowsetProps> & xProps, ULONG hCursor, CAccessorBag & aAccessors, IUnknown * pUnkCreator ) :_rQuery( rQuery ), _xProperties( xProps.Acquire() ), _hCursor( hCursor ), _pRowBufs(0), _pConnectionPointContainer( 0 ), _pRowsetNotification( 0 ), _pAsynchNotification( 0 ), _fForwardOnly( (_xProperties->GetPropertyFlags() & eLocatable) == 0), #pragma warning(disable : 4355) // 'this' in a constructor
_ColumnsInfo( cols, pidmap, _DBErrorObj, * ((IUnknown *) (IRowsetScroll *) this), _fForwardOnly ), _aAccessors( (IUnknown *) (IRowset *)this ), _DBErrorObj( * ((IUnknown *) (IRowset *) this), _mutex ), _impIUnknown(rControllingQuery, this), #pragma warning(default : 4355) // 'this' in a constructor
_PropInfo(), _fIsCategorized( fIsCategorized ), _fExtendedTypes( (_xProperties->GetPropertyFlags() & eExtendedTypes) != 0 ), _fHoldRows( (_xProperties->GetPropertyFlags() & eHoldRows) != 0 ), _fAsynchronous( (_xProperties->GetPropertyFlags() & eAsynchronous) != 0), _pRelatedRowset( 0 ), _pChapterRowbufs( 0 ) { Win4Assert(_hCursor != 0); if (_hCursor == 0) THROW(CException(E_NOINTERFACE));
if (pUnkOuter) _pControllingUnknown = pUnkOuter; else _pControllingUnknown = (IUnknown * )&_impIUnknown;
_DBErrorObj.SetInterfaceArray(cRowsetErrorIFs, apRowsetErrorIFs);
ULONG obRowRefcount, obRowWorkId; ULONG obChaptRefcount, obChaptId; _ColumnsInfo.SetColumnBindings( rQuery, _hCursor, obRowRefcount, obRowWorkId, obChaptRefcount, obChaptId );
//
// GetBindings for each accessor in bag, and use them to create accessor
// in IRowset
//
// only CAccessors can be used by commands
CAccessorBase * pAccBase = (CAccessorBase *)aAccessors.First(); while ( 0 != pAccBase ) { DBCOUNTITEM cBindings; DBBINDING * rgBindings; DBACCESSORFLAGS dwAccessorFlags; SCODE sc = pAccBase->GetBindings( &dwAccessorFlags, &cBindings, &rgBindings);
if ( FAILED( sc ) ) THROW( CException( sc ) ); HACCESSOR hAccessor; sc = CreateAccessor(dwAccessorFlags, cBindings, rgBindings, 0, &hAccessor, 0); CoTaskMemFree(rgBindings); //cleanup from GetBindings
if (FAILED(sc)) THROW( CException( sc ) ); //
// inherited accessors are accessed through same hAccessor as original.
// Set parent of newly created accessor so that we can link the 2 copies.
// Client never knows the direct HACESSOR for the inherited accessor.
// All accessor methods check bag for an accessor with a match on
// the parent or the creator.
//
((CAccessorBase *)hAccessor)->SetParent(pAccBase); //
// Increment inheritor count for parent accessor
//
pAccBase->IncInheritors(); pAccBase = (CAccessor *)aAccessors.Next(); }
_pRowBufs = new CRowBufferSet( _fForwardOnly, obRowRefcount, obRowWorkId, obChaptRefcount, obChaptId );
*ppMyUnk = ((IUnknown *)&_impIUnknown);
// can't fail after this or _pRowBufs will leak
(*ppMyUnk)->AddRef(); rQuery.AddRef();
if ( 0 != pUnkCreator ) { _xUnkCreator.Set( pUnkCreator ); _xUnkCreator->AddRef(); }
} //CRowset
//+---------------------------------------------------------------------------
//
// Member: CRowset::~CRowset, public
//
// Synopsis: Destroy the rowset and its component objects
//
//----------------------------------------------------------------------------
CRowset::~CRowset() { Win4Assert( _impIUnknown._ref == 0 ); Win4Assert( _hCursor != 0 );
delete _pRowBufs;
// free cursor will fail if the pipe is broken
TRY { if ( !_pRowsetNotification.IsNull() ) _pRowsetNotification->OnRowsetChange( this, DBREASON_ROWSET_RELEASE, DBEVENTPHASE_DIDEVENT, TRUE); _rQuery.FreeCursor( _hCursor ); } CATCH( CException, e ) { } END_CATCH;
if ( !_pRowsetNotification.IsNull() ) _pRowsetNotification->StopNotifications(); delete _pConnectionPointContainer;
_rQuery.Release(); } //~CRowset
//+-------------------------------------------------------------------------
//
// Member: CRowset::RealQueryInterface, public
//
// Synopsis: Get a reference to another interface on the cursor
//
// Notes: ref count is incremented inside QueryInterface
//
//--------------------------------------------------------------------------
SCODE CRowset::RealQueryInterface( REFIID ifid, void * *ppiuk ) { SCODE sc = S_OK;
*ppiuk = 0;
// note -- IID_IUnknown covered in QueryInterface
if ( IID_IRowset == ifid ) { *ppiuk = (void *) (IRowset *) this; } else if ( IID_IAccessor == ifid ) { *ppiuk = (void *) (IAccessor *) this; } else if ( IID_IRowsetInfo == ifid ) { *ppiuk = (void *) (IRowsetInfo *) this; } else if ( IID_IColumnsInfo == ifid ) { *ppiuk = (void *) (IColumnsInfo *) &_ColumnsInfo; } else if (IID_ISupportErrorInfo == ifid) { *ppiuk = (void *) ((IUnknown *) (ISupportErrorInfo *) &_DBErrorObj); } else if ( IID_IConvertType == ifid ) { *ppiuk = (void *) (IConvertType *) this; } #if 0 // NEWFEATURE - not implemented now.
else if ( IID_IColumnsRowset == ifid ) { *ppiuk = (void *) (IColumnsRowset *) &_ColumnsInfo; } #endif // 0 // NEWFEATURE - not implemented now.
else if ( IID_IRowsetQueryStatus == ifid ) { *ppiuk = (void *) (IRowsetQueryStatus *) this; } else if ( IID_IServiceProperties == ifid ) { *ppiuk = (void *) (IServiceProperties *) this; } else if ( IID_IConnectionPointContainer == ifid ) { // Watch notifications are only supported over the
// bottom-most of a hierarchical rowset (the one with real rows)
BOOL fWatchable = ! _pRowBufs->IsChaptered() && (_xProperties->GetPropertyFlags() & eWatchable) != 0;
if ( 0 == _pConnectionPointContainer ) { TRY { XPtr<CConnectionPointContainer> xCPC( new CConnectionPointContainer( _fAsynchronous ? 3 : 1, * ((IUnknown *) (IRowsetScroll *) this), _DBErrorObj) );
if (_fAsynchronous) { _pAsynchNotification = new CRowsetAsynchNotification( _rQuery, _hCursor, this, _DBErrorObj, fWatchable ); _pRowsetNotification.Set( _pAsynchNotification ); } else { _pRowsetNotification.Set ( new CRowsetNotification( ) ); }
_pRowsetNotification->AddConnectionPoints( xCPC.GetPointer() ); _pConnectionPointContainer = xCPC.Acquire(); } CATCH( CException, e ) { sc = GetOleError( e ); } END_CATCH; }
if ( S_OK == sc ) { Win4Assert( 0 != _pConnectionPointContainer ); *ppiuk = (void *) (IConnectionPointContainer *) _pConnectionPointContainer; } } else if (! _fForwardOnly) { if ( IID_IRowsetScroll == ifid ) { *ppiuk = (void *) (IRowsetScroll *) this; } else if ( IID_IRowsetExactScroll == ifid ) { *ppiuk = (void *) (IRowsetExactScroll *) this; } else if ( IID_IRowsetLocate == ifid ) { *ppiuk = (void *) (IRowsetLocate *) this; } else if ( IID_IRowsetIdentity == ifid ) { *ppiuk = (void *) (IRowsetIdentity *) this; } else if ( IID_IChapteredRowset == ifid ) { Win4Assert( (_pChapterRowbufs != 0) == _fIsCategorized ); if (_pChapterRowbufs) { *ppiuk = (void *) (IChapteredRowset *) this; } } else if ( _fAsynchronous ) { if ( IID_IDBAsynchStatus == ifid ) { *ppiuk = (void *) (IDBAsynchStatus *) this; } else if ( IID_IRowsetAsynch == ifid ) { *ppiuk = (void *) (IRowsetAsynch *) this; } else if (IID_IRowsetWatchRegion == ifid) { *ppiuk = (void *) (IRowsetWatchRegion *) this; } else if (IID_IRowsetWatchAll == ifid) { *ppiuk = (void *) (IRowsetWatchAll *) this; } } }
if ( 0 == *ppiuk ) { sc = E_NOINTERFACE; }
return sc; }
//+-------------------------------------------------------------------------
//
// Member: CRowset::CImpIUnknown::AddRef, public
//
// Synopsis: Reference the cursor.
//
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CRowset::CImpIUnknown::AddRef(void) { long ref = InterlockedIncrement( &_ref );
if ( ref > 0 ) _rControllingQuery.AddRef();
return ref ; } //AddRef
//+-------------------------------------------------------------------------
//
// Member: CRowset::CImpIUnknown::Release, public
//
// Synopsis: De-Reference the cursor.
//
// Effects: If the ref count goes to 0 then the cursor is deleted.
//
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CRowset::CImpIUnknown::Release(void) { long ref = InterlockedDecrement( &_ref );
if ( ref >= 0 ) _rControllingQuery.Release(); // may cause a delete of the rowset
return ref; } //Release
//+---------------------------------------------------------------------------
//
// Member: CRowset::GetProperties, public
//
// Synopsis: Return information about the capabilities of the rowset
//
// Arguments: [cPropertyIDSets] - number of property ID sets or zero
// [rgPropertyIDSets] - array of desired property ID sets or NULL
// [pcPropertySets] - number of DBPROPSET structures returned
// [prgPropertySets] - array of returned DBPROPSET structures
//
//
// Returns: SCODE
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::GetProperties( const ULONG cPropertyIDSets, const DBPROPIDSET rgPropertyIDSets[], ULONG * pcPropertySets, DBPROPSET ** prgPropertySets) { _DBErrorObj.ClearErrorInfo();
if ( (0 != cPropertyIDSets && 0 == rgPropertyIDSets) || 0 == pcPropertySets || 0 == prgPropertySets ) { if (pcPropertySets) *pcPropertySets = 0; if (prgPropertySets) *prgPropertySets = 0; return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetInfo); }
SCODE scResult = S_OK; *pcPropertySets = 0; *prgPropertySets = 0;
TRY { //
// Update ROWSETQUERYSTATUS property
//
DWORD dwStatus; _rQuery.GetQueryStatus( _hCursor, dwStatus );
_xProperties->SetValLong( CMRowsetProps::eid_DBPROPSET_MSIDXS_ROWSET_EXT, CMRowsetProps::eid_MSIDXSPROPVAL_ROWSETQUERYSTATUS, dwStatus );
scResult = _xProperties->GetProperties( cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets ); if (FAILED(scResult)) _DBErrorObj.PostHResult(scResult, IID_IRowsetInfo); } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetInfo); scResult = GetOleError(e); } END_CATCH;
return scResult; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::RatioFinished, public
//
// Synopsis: Returns the completion status of the query.
//
// Arguments: [pulDenominator] - on return, denominator of fraction
// [pulNumerator] - on return, numerator of fraction
// [pcRows] - on return, number of rows
// [pfNewRows] - on return, TRUE if new rows in the table
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::RatioFinished( DBCOUNTITEM * pulDenominator, DBCOUNTITEM * pulNumerator, DBCOUNTITEM * pcRows, BOOL * pfNewRows) /*const*/ { _DBErrorObj.ClearErrorInfo();
SCODE scResult = S_OK;
if (0 == pulDenominator || 0 == pulNumerator || 0 == pcRows || 0 == pfNewRows) return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetAsynch);
TRY { *pcRows = 0; _rQuery.RatioFinished( _hCursor, *pulDenominator, *pulNumerator, *pcRows, *pfNewRows );
#if CIDBG
if ( _fForwardOnly ) Win4Assert( *pulDenominator == *pulNumerator ); else Win4Assert( *pulDenominator >= *pulNumerator ); #endif // CIDBG
} CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetAsynch); scResult = GetOleError(e); } END_CATCH;
return scResult; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::AddRefRows, public
//
// Synopsis: Increment the ref. count of a set of row handles
//
// Arguments: [cRows] -- Number of row handles in rghRows
// [rghRows] -- Array of HROWs to be ref. counted
// [rgRefCounts] -- Remaining reference counts on rows (optional)
// [rgRowStatus] -- Status for each row (optional)
//
// Returns: SCODE, DB_E_BADROWHANDLE if a bad row handle is passed in.
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CRowset::AddRefRows( DBCOUNTITEM cRows, const HROW rghRows [], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[]) { _DBErrorObj.ClearErrorInfo();
if (0 == _pRowBufs) return _DBErrorObj.PostHResult(E_FAIL, IID_IRowset);
SCODE scResult = S_OK; TRY { _pRowBufs->AddRefRows(cRows, rghRows, rgRefCounts, rgRowStatus); } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowset); scResult = GetOleError(e); } END_CATCH;
return scResult; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::ReleaseRows, public
//
// Synopsis: Release a set of row handles
//
// Arguments: [cRows] -- Number of row handles in rghRows
// [rghRows] -- Array of HROWs to be released
// [rgRowOptions] -- Reserved for future use (optional)
// [rgRefCounts] -- Remaining reference counts on rows (optional)
// [rgRowStatus] -- Status for each row (optional)
//
// Returns: SCODE, DB_E_BADROWHANDLE if a bad row handle is passed in.
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CRowset::ReleaseRows( DBCOUNTITEM cRows, const HROW rghRows [], DBROWOPTIONS rgRowOptions[], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[]) { _DBErrorObj.ClearErrorInfo();
if (0 == _pRowBufs) return _DBErrorObj.PostHResult(E_FAIL, IID_IRowset);
// if (0 != rgRowOptions)
// return E_FAIL;
SCODE scResult = S_OK; TRY { BOOL fNotify = FALSE; ULONG * pRefCounts = rgRefCounts; DBROWSTATUS * pRowStatus = rgRowStatus;
XArray<ULONG> xrgRefCounts; XArray<DBROWSTATUS> xrgRowStatus;
if ( !_pRowsetNotification.IsNull() && _pRowsetNotification->IsNotifyActive() ) { fNotify = TRUE; if ( 0 == pRefCounts ) { xrgRefCounts.Init( (unsigned) cRows); pRefCounts = xrgRefCounts.GetPointer(); } if ( 0 == pRowStatus ) { xrgRowStatus.Init( (unsigned) cRows); pRowStatus = xrgRowStatus.GetPointer(); } }
scResult = _pRowBufs->ReleaseRows(cRows, rghRows, pRefCounts, pRowStatus);
if ( fNotify ) { ULONG cRowsToNotify = 0; for (ULONG i=0; i<cRows; i++) if ( 0 == pRefCounts[i] && DBROWSTATUS_S_OK == pRowStatus[i] ) cRowsToNotify++;
if (cRowsToNotify) { XGrowable<HROW,20> xrghRows(cRowsToNotify);
for (cRowsToNotify=0, i=0; i<cRows; i++) if ( 0 == pRefCounts[i] && DBROWSTATUS_S_OK == pRowStatus[i] ) { xrghRows[cRowsToNotify] = rghRows[i]; cRowsToNotify++; }
_pRowsetNotification->OnRowChange( this, cRowsToNotify, xrghRows.Get(), DBREASON_ROW_RELEASE, DBEVENTPHASE_DIDEVENT, TRUE); } } } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowset); scResult = GetOleError(e); } END_CATCH;
return scResult; }
//+---------------------------------------------------------------------------
//
// Macro: CheckCrowsArgs
//
// Synopsis: Check common error conditions on cRows and pcRowsObtained
// for GetRowsXxxx methods.
//
// Arguments: [cRows] -- Number of rows to return
// [pcRowsObtained] -- On return, number of rows actually
// fetched
//
// Returns: SCODE
//
// Notes: Needs to be a macro instead of an inline function because
// it returns from the calling method.
//
//--------------------------------------------------------------------------
#define CheckCrowsArgs(cRows, pcRowsObtained) \
if (0 == pcRowsObtained) \ return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowset); \ *pcRowsObtained = 0; \ if (cRows == 0) \ return S_OK;
//+---------------------------------------------------------------------------
//
// Member: CRowset::GetRowsAt, public
//
// Synopsis: Fetch data starting at some starting bookmark
//
// Arguments: [hRegion] -- handle to watch region
// [hChapter] -- Chapter in a multiset cursor
// [cbBookmark] -- Size of bookmark for starting position
// [pBookmark] -- Pointer to bookmark for starting position
// [lRowsOffset] -- Number of row handles in rghRows
// [cRows] -- Number of rows to return
// [pcRowsObtained] -- On return, number of rows actually
// fetched
// [prghRows] -- Array of HROWs to be returned
//
// Returns: SCODE, E_INVALIDARG for bad parameters, DB_E_BADBOOKMARK
// if the starting bookmark is invalid
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CRowset::GetRowsAt( HWATCHREGION hRegion, HCHAPTER hChapter, DBBKMARK cbBookmark, const BYTE* pBookmark, DBROWOFFSET lRowsOffset, DBROWCOUNT cRows, DBCOUNTITEM * pcRowsObtained, HROW * * prghRows ) { _DBErrorObj.ClearErrorInfo();
SCODE scResult = S_OK;
CheckCrowsArgs( cRows, pcRowsObtained );
TRY { CI_TBL_BMK bmk = _MapBookmark(cbBookmark, pBookmark); CI_TBL_CHAPT chapt = _MapChapter(hChapter);
CRowSeekAt rowSeek( hRegion, chapt, (LONG) lRowsOffset, bmk );
scResult = _FetchRows(rowSeek, cRows, pcRowsObtained, prghRows); if (FAILED(scResult)) _DBErrorObj.PostHResult(scResult, IID_IRowsetLocate); else if ( !_pRowsetNotification.IsNull() && *pcRowsObtained != 0 && _pRowsetNotification->IsNotifyActive() ) { _pRowsetNotification->OnRowChange( this, *pcRowsObtained, *prghRows, DBREASON_ROW_ACTIVATE, DBEVENTPHASE_DIDEVENT, TRUE); } } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetLocate); scResult = GetOleError(e); } END_CATCH;
return scResult; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::GetRowsByBookmark, public
//
// Synopsis: Fetch data from a set of bookmarks
//
// Arguments: [hChapter] -- Chapter in a multiset cursor
// [cRows] -- Number of input bookmarks and rows to return
// [rgcbBookmark] -- Array of bookmark sizes
// [ppBookmarks] -- Array of pointers to bookmarks
// [rghRows] -- Array of HROWs returned
// [rgRowStatus] -- Array for per-row status (optional)
//
// Returns: SCODE, E_INVALIDARG for bad parameters, DB_E_BADBOOKMARK
// if the starting bookmark is invalid
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CRowset::GetRowsByBookmark( HCHAPTER hChapter, DBCOUNTITEM cRows, const DBBKMARK rgcbBookmark[], const BYTE * ppBookmarks[], HROW rghRows[], DBROWSTATUS rgRowStatus[] ) { _DBErrorObj.ClearErrorInfo();
SCODE scResult = S_OK;
if (0 == ppBookmarks || 0 == rgcbBookmark || 0 == rghRows) return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetLocate);
if (cRows == 0) return scResult;
TRY { //
// Map the input bookmarks to work IDs. If we see an invalid
// bookmark, it will get turned into widInvalid, and its lookup
// will fail.
//
XArray<CI_TBL_BMK> paBmk( (unsigned) cRows );
for (unsigned i=0; i < cRows; i++) { DBROWSTATUS sc = _MapBookmarkNoThrow( rgcbBookmark[i], ppBookmarks[i], paBmk[i] ); }
CI_TBL_CHAPT chapt = _MapChapter(hChapter);
CRowSeekByBookmark rowSeek( chapt, (ULONG) cRows, paBmk.Acquire() );
DBCOUNTITEM cRowsObtained; TRY { scResult = _FetchRows(rowSeek, cRows, &cRowsObtained, &rghRows); } CATCH( CException, e ) { scResult = e.GetErrorCode(); } END_CATCH
//
// Return the array of row statuses
//
unsigned cErrors = 0; for (i=0; i < rowSeek.GetValidStatuses(); i++) { SCODE scTemp = rowSeek.GetStatus(i); if (0 != rgRowStatus) rgRowStatus[i] = ScodeToRowstatus( scTemp );
if (S_OK != scTemp) { //
// The HROW array returned by _FetchRows is compressed,
// skipping entries for rows that had errors. Insert
// a DB_NULL_HROW entry for this row.
//
if ( i != cRows-1 ) { memmove( &rghRows[i+1], &rghRows[i], (unsigned) ((cRows-i)-1) * sizeof (HROW)); } rghRows[i] = DB_NULL_HROW;
//
// If the returned error is DB_E_BADBOOKMARK,
// call MapBookmarkNoThrow again to distinguish
// E_INVALIDARG cases.
//
if (DB_E_BADBOOKMARK == scTemp && 0 != rgRowStatus) { CI_TBL_BMK bmkTemp; DBROWSTATUS rsTemp = _MapBookmarkNoThrow(rgcbBookmark[i], ppBookmarks[i], bmkTemp); if (rsTemp != DBROWSTATUS_S_OK) { rgRowStatus[i] = rsTemp; } } cErrors++; } } Win4Assert( rowSeek.GetValidStatuses() == cRows );
if (SUCCEEDED(scResult) && cErrors > 0) scResult = (cErrors == cRows) ? DB_E_ERRORSOCCURRED : DB_S_ERRORSOCCURRED;
if (FAILED(scResult)) _DBErrorObj.PostHResult(scResult, IID_IRowsetLocate); else if ( !_pRowsetNotification.IsNull() && _pRowsetNotification->IsNotifyActive() ) _pRowsetNotification->OnRowChange( this, cRows, rghRows, DBREASON_ROW_ACTIVATE, DBEVENTPHASE_DIDEVENT, TRUE); }
CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetLocate); scResult = GetOleError(e); Win4Assert(FAILED(scResult)); } END_CATCH;
return scResult; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::Compare, public
//
// Synopsis: Compare two bookmarks
//
// Arguments: [hChapter] -- chapter
// [cbBookmark1] -- Size of first bookmark
// [pBookmark1] -- Pointer to first bookmark
// [cbBookmark2] -- Size of second bookmark
// [pBookmark2] -- Pointer to second bookmark
// [pdwComparison] - on return, hased value of bookmark
//
// Returns: SCODE, E_INVALIDARG if cbBookmark is zero or if pBookmark or
// pdwComparison is NULL, DB_E_BADBOOKMARK for other invalid
// bookmarks.
//
// Notes:
//
//--------------------------------------------------------------------------
STDMETHODIMP CRowset::Compare( HCHAPTER hChapter, DBBKMARK cbBookmark1, const BYTE* pBookmark1, DBBKMARK cbBookmark2, const BYTE* pBookmark2, DBCOMPARE * pdwComparison) /*const*/ { _DBErrorObj.ClearErrorInfo();
SCODE sc = S_OK;
if (0 == pdwComparison) return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetLocate);
TRY { ULONG dwHash1 = _MapBookmark(cbBookmark1, pBookmark1); ULONG dwHash2 = _MapBookmark(cbBookmark2, pBookmark2);
//
// Set to non-comparable. This is used later to see if we've
// successfully determined the relative order.
//
*pdwComparison = DBCOMPARE_NOTCOMPARABLE;
if (dwHash1 == dwHash2) { *pdwComparison = DBCOMPARE_EQ; } else if ( 1 == cbBookmark1 || 1 == cbBookmark2 ) { *pdwComparison = DBCOMPARE_NE; } else { CI_TBL_CHAPT chapt = _MapChapter(hChapter); _rQuery.Compare( _hCursor, chapt, dwHash1, dwHash2, (DWORD) (*pdwComparison) ); } } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetLocate); sc = GetOleError(e); } END_CATCH;
return sc; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::_MapChapter, private
//
// Synopsis: Map a chapter mark to a ULONG internal chapter mark.
//
// Arguments: [hChapter] -- handle of chapter
//
// Returns: Chapter as an I4
//
// Notes: A null chapter on a categorized rowset means to operate
// over the entire rowset, not an individual chapter.
//
//--------------------------------------------------------------------------
CI_TBL_CHAPT CRowset::_MapChapter( HCHAPTER hChapter ) const { CI_TBL_CHAPT chapt = (CI_TBL_CHAPT) hChapter; Win4Assert (DB_NULL_HCHAPTER == 0);
if ( !_fIsCategorized && DB_NULL_HCHAPTER != hChapter ) { THROW( CException( DB_E_BADCHAPTER )); }
return chapt; } //_MapChapter
//+---------------------------------------------------------------------------
//
// Member: CRowset::_MapBookmarkNoThrow, private
//
// Synopsis: Return a 32 bit hash value for a particular bookmark.
// Don't throw on errors.
//
// Arguments: [cbBookmark] -- Size of bookmark
// [pBookmark] -- Pointer to bookmark
//
// Notes: For IRowsetLocate::Hash and IRowsetLocate::GetRowsByBookmark
// which want to continue processing on bookmark errors. Unlike
// _MapBookmark, DBBMK_FIRST and DBBMK_LAST are invalid.
//
// Returns: DBROWSTATUS, hash value (identity function, also the workid
// value for the table) is returned in rBmk
//
//--------------------------------------------------------------------------
DBROWSTATUS CRowset::_MapBookmarkNoThrow( DBBKMARK cbBookmark, const BYTE* pBookmark, CI_TBL_BMK & rBmk) const { Win4Assert( !_fForwardOnly );
rBmk = widInvalid;
if (0 == cbBookmark || 0 == pBookmark) return DBROWSTATUS_E_INVALID;
if (cbBookmark == 1) { if (*(BYTE *)pBookmark == DBBMK_FIRST || *(BYTE *)pBookmark == DBBMK_LAST || *(BYTE *)pBookmark == DBBMK_INVALID) return DBROWSTATUS_E_INVALID; else return DBROWSTATUS_E_INVALID; //DB_E_BADBOOKMARK ???
} else if (cbBookmark == sizeof (CI_TBL_BMK)) { rBmk = *(UNALIGNED CI_TBL_BMK *) pBookmark;
if (rBmk == WORKID_TBLFIRST || rBmk == WORKID_TBLLAST) return DBROWSTATUS_E_INVALID; return DBROWSTATUS_S_OK; }
return DBROWSTATUS_E_INVALID; //DB_E_BADBOOKMARK ???
} //_MapBookmarkNoThrow
//+---------------------------------------------------------------------------
//
// Member: CRowset::_MapBookmark, private
//
// Synopsis: Convert a bookmark into an internal form.
//
// Arguments: [cbBookmark] -- Size of bookmark
// [pBookmark] -- Pointer to bookmark
//
// Returns: ULONG, hash value (identity function, also the workid
// value for the table)
//
//--------------------------------------------------------------------------
CI_TBL_BMK CRowset::_MapBookmark( DBBKMARK cbBookmark, const BYTE* pBookmark) const { Win4Assert( !_fForwardOnly );
WORKID WorkID = widInvalid; Win4Assert( sizeof WORKID == sizeof CI_TBL_BMK );
if (0 == cbBookmark || 0 == pBookmark) THROW(CException(E_INVALIDARG));
if (cbBookmark == 1) { if (*(BYTE *)pBookmark == DBBMK_FIRST) WorkID = WORKID_TBLFIRST;
else if (*(BYTE *)pBookmark == DBBMK_LAST) WorkID = WORKID_TBLLAST; } else if (cbBookmark == sizeof (CI_TBL_BMK)) { WorkID = *(UNALIGNED CI_TBL_BMK *) pBookmark; }
if (WorkID == widInvalid) THROW(CException(DB_E_BADBOOKMARK));
return WorkID; } //_MapBookmark
//+---------------------------------------------------------------------------
//
// Member: CRowset::Hash, public
//
// Synopsis: Returns an array of 32 bit hash values for bookmarks
//
// Arguments: [hChapter] -- chapter
// [cBookmarks] -- # of bmks to hash
// [rgcbBM] -- Sizes of each bookmark
// [ppBM] -- Pointers to each bookmark
// [rgHashedValues] -- on return, hashed values of bookmarks
// [rgBookmarkStatus] -- per-bookmark status (optional)
//
// Returns: SCODE, E_INVALIDARG if any cbBookmark is zero,
// DB_E_BADBOOKMARK for other invalid bookmarks.
//
//--------------------------------------------------------------------------
STDMETHODIMP CRowset::Hash( HCHAPTER hChapter, DBBKMARK cBookmarks, const DBBKMARK rgcbBM[], const BYTE * ppBM[], DBHASHVALUE rgHashedValues[], DBROWSTATUS rgBookmarkStatus[] ) { _DBErrorObj.ClearErrorInfo();
SCODE scResult = S_OK; ULONG cErrors = 0;
if (0 == rgcbBM || 0 == ppBM || 0 == rgHashedValues) return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetLocate);
TRY { CI_TBL_CHAPT chapt = _MapChapter(hChapter);
for (ULONG i = 0; i < cBookmarks; i++) { CI_TBL_BMK bmk; DBROWSTATUS rs = _MapBookmarkNoThrow( rgcbBM[i], ppBM[i], bmk ); rgHashedValues[i] = bmk;
if (rs != DBROWSTATUS_S_OK) { rgHashedValues[i] = 0; cErrors++; } if (0 != rgBookmarkStatus) rgBookmarkStatus[i] = rs; }
if (cErrors) scResult = (cErrors == cBookmarks) ? DB_E_ERRORSOCCURRED : DB_S_ERRORSOCCURRED;
if (FAILED(scResult)) _DBErrorObj.PostHResult(scResult, IID_IRowsetLocate); } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetLocate); scResult = GetOleError(e); } END_CATCH;
return scResult; } //Hash
//+---------------------------------------------------------------------------
//
// Member: CRowset::GetApproximatePosition, public
//
// Synopsis: Returns the approximate position of a bookmark
//
// Arguments: [hChapter] -- chapter
// [cbBookmark] -- size of bookmark
// [pBookmark] -- bookmark
// [pulPosition] -- return approx row number of bookmark
// [pulRows] -- returns approx # of rows in cursor or
// 1 + approx rows if not at quiescence
//
// Returns: SCODE - the status of the operation.
//
//--------------------------------------------------------------------------
STDMETHODIMP CRowset::GetApproximatePosition( HCHAPTER hChapter, DBBKMARK cbBookmark, const BYTE * pBookmark, DBCOUNTITEM * pulPosition, DBCOUNTITEM * pulRows) /*const*/ { _DBErrorObj.ClearErrorInfo();
Win4Assert( !_fForwardOnly );
SCODE sc = S_OK;
TRY { DBCOUNTITEM ulNumerator, ulDenominator;
CI_TBL_BMK bmk = WORKID_TBLFIRST;
if (cbBookmark != 0) bmk = _MapBookmark(cbBookmark, pBookmark);
CI_TBL_CHAPT chapt = _MapChapter(hChapter); _rQuery.GetApproximatePosition( _hCursor, chapt, bmk, &ulNumerator, &ulDenominator );
if (cbBookmark) *pulPosition = ulNumerator; if (pulRows) *pulRows = ulDenominator; } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetScroll); sc = GetOleError(e); } END_CATCH;
return sc; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::GetExactPosition, public
//
// Synopsis: Returns the exact position of a bookmark
//
// Arguments: [hChapter] -- chapter
// [cbBookmark] -- size of bookmark
// [pBookmark] -- bookmark
// [pulPosition] -- return approx row number of bookmark
// [pulRows] -- returns approx # of rows in cursor or
// 1 + approx rows if not at quiescence
//
// Returns: SCODE - the status of the operation.
//
// Notes: We don't distinguish between exact and approximate position.
// IRowsetExactScroll is implemented only because ADO 1.5
// started QI'ing for it.
//
//--------------------------------------------------------------------------
STDMETHODIMP CRowset::GetExactPosition( HCHAPTER hChapter, DBBKMARK cbBookmark, const BYTE * pBookmark, DBCOUNTITEM * pulPosition, DBCOUNTITEM * pulRows) /*const*/ { _DBErrorObj.ClearErrorInfo();
Win4Assert( !_fForwardOnly );
SCODE sc = S_OK;
TRY { DBCOUNTITEM ulNumerator, ulDenominator;
CI_TBL_BMK bmk = WORKID_TBLFIRST;
if (cbBookmark != 0) bmk = _MapBookmark(cbBookmark, pBookmark);
CI_TBL_CHAPT chapt = _MapChapter(hChapter); _rQuery.GetApproximatePosition( _hCursor, chapt, bmk, &ulNumerator, &ulDenominator );
if (cbBookmark) *pulPosition = ulNumerator; if (pulRows) *pulRows = ulDenominator; } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetScroll); sc = GetOleError(e); } END_CATCH;
return sc; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::GetRowsAtRatio, public
//
// Synopsis: Fetch data starting at some ratio in the cursor.
//
// Arguments: [hRegion] -- handle to watch region
// [hChapter] -- Chapter in a multiset cursor
// [ulNumerator] -- numerator or ratio fraction
// [ulDenominator] -- denominator or ratio fraction
// [cRows] -- Number of rows to return
// [pcRowsObtained] -- On return, number of rows actually
// fetched.
// [prghRows] -- Array of HROWs to be released
//
// Returns: SCODE, E_INVALIDARG for bad parameters, DB_E_BADBOOKMARK
// if the starting bookmark is invalid
//
// Notes:
//
// History: 14 Dec 1994 Alanw Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CRowset::GetRowsAtRatio( HWATCHREGION hRegion, HCHAPTER hChapter, DBCOUNTITEM ulNumerator, DBCOUNTITEM ulDenominator, DBROWCOUNT cRows, DBCOUNTITEM * pcRowsObtained, HROW * * prghRows ) { _DBErrorObj.ClearErrorInfo();
CheckCrowsArgs( cRows, pcRowsObtained );
SCODE scResult = S_OK;
TRY { CI_TBL_CHAPT chapt = _MapChapter(hChapter);
CRowSeekAtRatio rowSeek( hRegion, chapt, (ULONG) ulNumerator, (ULONG) ulDenominator ); scResult = _FetchRows(rowSeek, cRows, pcRowsObtained, prghRows); if (FAILED(scResult)) _DBErrorObj.PostHResult(scResult, IID_IRowsetScroll); else if ( !_pRowsetNotification.IsNull() && *pcRowsObtained != 0 && _pRowsetNotification->IsNotifyActive() ) { _pRowsetNotification->OnRowChange( this, *pcRowsObtained, *prghRows, DBREASON_ROW_ACTIVATE, DBEVENTPHASE_DIDEVENT, TRUE); } } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetScroll); scResult = GetOleError(e); } END_CATCH;
return scResult; }
#ifdef _WIN64
//+---------------------------------------------------------------------------
//
// Member: CRowset::_ConvertOffsetsToPointers, private
//
// Synopsis: Runs through a row buffer converting offsets to pointers
//
// Arguments: [pbRows] -- Buffer with row data
// [pbBias] -- Bias for offsets to pointers
// [cRows] -- Number of rows in the buffer
// [pArrayAlloc] -- buffer to hold extra array pointers
//
// History: 2 Aug 95 dlee created
// 1 Sep 99 KLam Reinstated
//
//----------------------------------------------------------------------------
void CRowset::_ConvertOffsetsToPointers( BYTE * pbRows, BYTE * pbBias, unsigned cRows, CFixedVarAllocator *pArrayAlloc ) { if ( !_fPossibleOffsetConversions ) return;
BOOL fAnyOffsets = FALSE;
CTableColumnSet const & rCols = _ColumnsInfo.GetColumnBindings(); unsigned cbRowWidth = _ColumnsInfo.GetRowWidth();
for ( unsigned col = 0; col < rCols.Count(); col++ ) { CTableColumn const & rColumn = *rCols.Get( col );
// if this assert isn't true someday, add an if on this condition
Win4Assert( rColumn.IsValueStored() );
VARTYPE vt = rColumn.GetStoredType();
if ( ( CTableVariant::IsByRef( vt ) ) && ( VT_CLSID != vt ) ) { fAnyOffsets = TRUE; BYTE *pbRow = pbRows; BYTE *pbData = pbRow + rColumn.GetValueOffset();
for ( unsigned row = 0; row < cRows; row++, pbData += cbRowWidth, pbRow += cbRowWidth ) { // Even stat props can be null if they came from a
// summary catalog.
tbDebugOut(( DEB_TRACE, "CRowset::_ConvertOffsetsToPointer, Bias: 0x%I64x Row: 0x%I64x Data: 0x%I64x Type: %d New Alloc: 0x%I64x\n", pbBias, pbRow, pbData, vt, pArrayAlloc ));
if (! rColumn.IsNull( pbRow ) ) { if ( VT_VARIANT == vt ) { if (! rColumn.IsDeferred( pbRow ) ) ((CTableVariant *) pbData)->FixDataPointers( pbBias, pArrayAlloc ); } else { Win4Assert( 0 == ( vt & VT_VECTOR ) ); * (BYTE **) pbData = pbBias + (* (ULONG *) pbData ); } } } } }
_fPossibleOffsetConversions = fAnyOffsets; } //_ConvertOffsetsToPointers
#endif // _WIN64
//+---------------------------------------------------------------------------
//
// Member: CRowset::_FetchRows, private
//
// Synopsis: Return handles to rows in the table
//
// Effects: Rows are read from the table and buffered locally. An
// array of handles to the rows is returned.
//
// Arguments: [rSeekDesc] - seek method and parameters
// [cRows] - number of rows desired
// [pcRowsReturned] - pointer to where number of rows is returned
// [prghRows] - pointer to pointer to where row handles are
// returned, or pointer to zero if row handle
// array should be allocated
//
// Returns: error code
//
// Notes:
//
//----------------------------------------------------------------------------
SCODE CRowset::_FetchRows( CRowSeekDescription & rSeekDesc, DBROWCOUNT cRows, DBCOUNTITEM * pcRowsReturned, HROW * * prghRows ) { SCODE scResult = S_OK;
Win4Assert( 0 != pcRowsReturned );
if (0 == prghRows) { THROW(CException(E_INVALIDARG)); }
if (0 == cRows) { *pcRowsReturned = 0; return scResult; }
BOOL fFwdFetch = TRUE; if ( cRows < 0 ) { fFwdFetch = FALSE; cRows = -cRows; // cRows now has its absolute value
}
Win4Assert( cRows > 0 );
BOOL fRowCountTrimmed = FALSE;
if (cRows > MAX_ROW_FETCH) { cRows = MAX_ROW_FETCH; fRowCountTrimmed = TRUE; }
XArrayOLE<HROW> ahRows; HROW *pHRows; if ( 0 == *prghRows ) { ahRows.Init( (unsigned) cRows ); pHRows = ahRows.GetPointer(); } else { pHRows = *prghRows; }
DBCOUNTITEM cRowsSoFar = 0; // number of rows successfully transferred.
CRowSeekDescription * pNextSeek = &rSeekDesc;
TRY { XPtr<CRowSeekDescription> pRowSeekPrevious(0); ULONG cbRowWidth = _ColumnsInfo.GetRowWidth();
do { XPtr<CFixedVarAllocator> xAlloc( new CFixedVarAllocator( FALSE, FALSE, cbRowWidth, 0 ));
CGetRowsParams FetchParams( (ULONG) (cRows - cRowsSoFar), fFwdFetch, cbRowWidth, xAlloc.GetReference() );
// Get the row data
XPtr<CRowSeekDescription> xRowSeekOut(0); scResult = _rQuery.GetRows( _hCursor, *pNextSeek, FetchParams, xRowSeekOut ); if (FAILED(scResult)) { #if CIDBG
if (E_FAIL == scResult) tbDebugOut((DEB_WARN, "CRowset::_FetchRows - E_FAIL ret'd by GetRows\n")); #endif // CIDBG
break; }
if ( 0 != FetchParams.RowsTransferred() ) { Win4Assert( !xAlloc->IsBasedMemory() );
XPtr<CRowBuffer> xRowBuf ( new CRowBuffer( _ColumnsInfo.GetColumnBindings(), cbRowWidth, FetchParams.RowsTransferred(), xAlloc ));
#ifdef _WIN64
// if this is a Win64 client talking with a Win32 server
// then we need to fix the row buffer since we passed in 0
// as the base address.
if ( FetchParams.GetReplyBase() != 0 ) { _fPossibleOffsetConversions = TRUE; void *pvRows; CTableColumnSet *pCol; SCODE sc = xRowBuf->Lookup( (unsigned)cRowsSoFar, &pCol, &pvRows, FALSE );
_ConvertOffsetsToPointers ( (BYTE *)pvRows, FetchParams.GetReplyBase(), FetchParams.RowsTransferred(), _pRowBufs->GetArrayAlloc() ); } #endif
_pRowBufs->Add( xRowBuf, rSeekDesc.IsByBmkRowSeek(), pHRows + cRowsSoFar );
cRowsSoFar += FetchParams.RowsTransferred(); } else { // One row didn't fit into an fsctl buffer.
if (! ( scResult == DB_S_ENDOFROWSET || scResult == DB_S_STOPLIMITREACHED || ( scResult == DB_S_ERRORSOCCURRED && rSeekDesc.IsByBmkRowSeek() ) ) ) { tbDebugOut(( DEB_WARN, "CRowset::_FetchRows, 0 rows, sc 0x%x\n", scResult )); }
Win4Assert( scResult == DB_S_ENDOFROWSET || scResult == DB_S_STOPLIMITREACHED || ( scResult == DB_S_ERRORSOCCURRED && rSeekDesc.IsByBmkRowSeek() ) ); }
if ( 0 != xRowSeekOut.GetPointer() ) { //
// Transfer results from the returned seek description
// (for the ByBookmark case), and update for the next
// transfer.
//
rSeekDesc.MergeResults( xRowSeekOut.GetPointer() ); delete pRowSeekPrevious.Acquire(); pRowSeekPrevious.Set( xRowSeekOut.Acquire() ); pNextSeek = pRowSeekPrevious.GetPointer(); }
Win4Assert( cRows >= 0 );
} while ( (DBCOUNTITEM) cRows > cRowsSoFar && 0 != pNextSeek && !pNextSeek->IsDone() && (S_OK == scResult || DB_S_BLOCKLIMITEDROWS == scResult ) ); } CATCH( CException, e ) { scResult = e.GetErrorCode(); #if CIDBG
if (E_FAIL == scResult) tbDebugOut((DEB_WARN, "CRowset::_FetchRows - E_FAIL from exception\n")); #endif // CIDBG
} END_CATCH;
if (DB_E_BADSTARTPOSITION == scResult) scResult = DB_S_ENDOFROWSET;
if ( fRowCountTrimmed && scResult == S_OK ) scResult = DB_S_ROWLIMITEXCEEDED;
if ( FAILED(scResult)) { ReleaseRows(cRowsSoFar, pHRows, 0, 0, 0); *pcRowsReturned = 0;
tbDebugOut((DEB_ITRACE, "CRowset::_FetchRows - error %x thrown\n", scResult)); QUIETTHROW( CException( scResult ) ); } else { if ( ( cRowsSoFar > 0 ) && ( 0 == *prghRows ) ) *prghRows = ahRows.Acquire();
*pcRowsReturned = cRowsSoFar; }
return( scResult ); }
//+---------------------------------------------------------------------------
//
// Member: CRowset::CreateAccessor, public
//
// Synopsis: Makes an accessor that a client can use to get data.
//
// Arguments: [dwAccessorFlags] -- read/write access requested
// [cBindings] -- # of bindings in rgBindings
// [rgBindings] -- array of bindings for the accessor to support
// [cbRowSize] -- ignored for IRowset
// [phAccessor] -- returns created accessor if all is ok
// [rgBindStatus] -- array of binding statuses
//
// Returns: SCODE error code
//
// History: 14 Dec 94 dlee Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::CreateAccessor( DBACCESSORFLAGS dwAccessorFlags, DBCOUNTITEM cBindings, const DBBINDING rgBindings[], DBLENGTH cbRowSize, HACCESSOR * phAccessor, DBBINDSTATUS rgBindStatus[]) { _DBErrorObj.ClearErrorInfo();
SCODE sc = S_OK;
if (0 == phAccessor || (0 != cBindings && 0 == rgBindings)) return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IAccessor);
// Make sure pointer is good while zeroing in case of a later error
*phAccessor = 0;
TRY { XPtr<CAccessor> Accessor( CreateAnAccessor( dwAccessorFlags, cBindings, rgBindings, rgBindStatus, _fExtendedTypes, (IUnknown *) (IRowset *)this, &_ColumnsInfo ) );
CLock lock( _mutex );
_aAccessors.Add( Accessor.GetPointer() );
*phAccessor = (Accessor.Acquire())->Cast(); } CATCH(CException, e) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IAccessor); sc = GetOleError(e); } END_CATCH;
return sc; } //CreateAccessor
//+---------------------------------------------------------------------------
//
// Member: IsValidFromVariantType
//
// Synopsis: If DBCONVERTFLAGS_FROMVARIANT is requested, the source type
// has to be a valid VARIANT type.
//
// Arguments: [wTypeIn] -- the source type
//
// Returns: TRUE -- the type is a valid VARIANT type
// FALSE -- otherwise
//
//----------------------------------------------------------------------------
inline BOOL IsValidFromVariantType( DBTYPE wTypeIn ) { DBTYPE wType = wTypeIn & VT_TYPEMASK;
return (! ((wType > VT_DECIMAL && wType < VT_I1) || (wType > VT_LPWSTR && wType < VT_FILETIME && wType != VT_RECORD) || (wType > VT_CLSID)) ); }
//+---------------------------------------------------------------------------
//
// Member: IsVariableLengthType
//
// Synopsis: checks to see DBCONVERTFLAGS_ISLONG is appropriate
//
// Arguments: [wTypeIn] -- the source type
//
// Returns: TRUE -- the type is variable length
// FALSE -- otherwise
//
//----------------------------------------------------------------------------
inline BOOL IsVariableLengthType( DBTYPE wTypeIn ) { DBTYPE wType = wTypeIn & VT_TYPEMASK;
return wType == DBTYPE_STR || wType == DBTYPE_BYTES || wType == DBTYPE_WSTR || wType == DBTYPE_VARNUMERIC; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::CanConvert, public
//
// Synopsis: Indicate whether a type conversion is valid.
//
// Arguments: [wFromType] -- source type
// [wToType] -- destination type
// [dwConvertFlags] -- read/write access requested
//
// Returns: S_OK if the conversion is available, S_FALSE otherwise.
// E_FAIL, E_INVALIDARG or DB_E_BADCONVERTFLAG on errors.
//
// History: 20 Nov 96 AlanW Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::CanConvert( DBTYPE wFromType, DBTYPE wToType, DBCONVERTFLAGS dwConvertFlags ) { _DBErrorObj.ClearErrorInfo();
SCODE sc = S_OK;
TRY { if (((dwConvertFlags & DBCONVERTFLAGS_COLUMN) && (dwConvertFlags & DBCONVERTFLAGS_PARAMETER)) || (dwConvertFlags & ~(DBCONVERTFLAGS_COLUMN | DBCONVERTFLAGS_PARAMETER | DBCONVERTFLAGS_ISFIXEDLENGTH | DBCONVERTFLAGS_ISLONG | DBCONVERTFLAGS_FROMVARIANT))) { sc = DB_E_BADCONVERTFLAG; } else if ( dwConvertFlags & DBCONVERTFLAGS_FROMVARIANT && !IsValidFromVariantType(wFromType) ) { sc = DB_E_BADTYPE; } else { BOOL fOk = CAccessor::CanConvertType( wFromType, wToType, _fExtendedTypes, _xDataConvert ); sc = fOk ? S_OK : S_FALSE; } if (FAILED(sc)) _DBErrorObj.PostHResult(sc, IID_IConvertType); } CATCH(CException, e) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IConvertType); sc = GetOleError(e); } END_CATCH;
return sc; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::GetBindings, public
//
// Synopsis: Returns an accessor's bindings
//
// Arguments: [hAccessor] -- accessor being queried
// [dwBindIO] -- returns read/write access of accessor
// [pcBindings] -- returns # of bindings in rgBindings
// [prgBindings] -- returns array of bindings
//
// Returns: SCODE error code
//
// History: 14 Dec 94 dlee Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::GetBindings( HACCESSOR hAccessor, DBACCESSORFLAGS * pdwBindIO, DBCOUNTITEM * pcBindings, DBBINDING * * prgBindings) /*const*/ { _DBErrorObj.ClearErrorInfo();
SCODE sc = S_OK;
if (0 == pdwBindIO || 0 == pcBindings || 0 == prgBindings) { // fill in error values where possible
if (pdwBindIO) *pdwBindIO = DBACCESSOR_INVALID; if (pcBindings) *pcBindings = 0; if (prgBindings) *prgBindings = 0;
return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IAccessor); }
*pdwBindIO = DBACCESSOR_INVALID; *pcBindings = 0; *prgBindings = 0;
TRY { CLock lock( _mutex ); CAccessor * pAccessor = (CAccessor *)_aAccessors.Convert( hAccessor ); pAccessor->GetBindings(pdwBindIO, pcBindings, prgBindings); } CATCH(CException, e) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IAccessor); sc = GetOleError(e); } END_CATCH;
return sc; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::AddRefAccessor, public
//
// Synopsis: Frees an accessor
//
// Arguments: [hAccessor] -- accessor being freed
// [pcRefCount] -- pointer to residual refcount (optional)
//
// Returns: SCODE error code
//
// History: 14 Dec 94 dlee Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::AddRefAccessor( HACCESSOR hAccessor, ULONG * pcRefCount ) { _DBErrorObj.ClearErrorInfo();
SCODE sc = S_OK;
TRY { CLock lock( _mutex ); _aAccessors.AddRef( hAccessor, pcRefCount ); } CATCH(CException, e) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IAccessor); sc = GetOleError(e); } END_CATCH;
return sc; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::ReleaseAccessor, public
//
// Synopsis: Frees an accessor
//
// Arguments: [hAccessor] -- accessor being freed
// [pcRefCount] -- pointer to residual refcount (optional)
//
// Returns: SCODE error code
//
// History: 14 Dec 94 dlee Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::ReleaseAccessor( HACCESSOR hAccessor, ULONG * pcRefCount ) { _DBErrorObj.ClearErrorInfo();
SCODE sc = S_OK;
TRY { CLock lock( _mutex ); _aAccessors.Release( hAccessor, pcRefCount ); } CATCH(CException, e) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IAccessor); sc = GetOleError(e); } END_CATCH;
return sc; } //ReleaseAccessor
//+---------------------------------------------------------------------------
//
// Member: CRowset::GetData, public
//
// Synopsis: Returns row data using an accessor
//
// Arguments: [hRow] -- handle of row whose data is returned
// [hAccessor] -- accessor used to retrieve the data
// [pData] -- where the data is written
//
// Returns: SCODE error code
//
// History: 14 Dec 94 dlee Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::GetData( HROW hRow, HACCESSOR hAccessor, void* pData) /*const*/ { _DBErrorObj.ClearErrorInfo();
SCODE sc = S_OK;
// NOTE: Null accessors are not supported, so don't need to worry about
// special casing for that.
if ( 0 == pData ) return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowset);
TRY { CLock lock( _mutex ); CAccessor * pAccessor = (CAccessor *)_aAccessors.Convert( hAccessor );
Win4Assert( pAccessor->IsRowDataAccessor() ); pAccessor->GetData(hRow, pData, *_pRowBufs, _rQuery, _ColumnsInfo, _xDataConvert ); } CATCH(CException, e) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowset); sc = GetOleError(e); } END_CATCH;
return sc; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::GetNextRows, public
//
// Synopsis: Return row data from the table
//
// Arguments: [hChapter] -- chapter to start at
// [cRowsToSkip] -- # of rows to skip
// [cRows] -- # of rows to try to return
// [pcRowsObtained] -- returns # of rows obtained
// [prghRows] -- returns array of rows
//
// Returns: SCODE error code
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::GetNextRows( HCHAPTER hChapter, DBROWOFFSET cRowsToSkip, DBROWCOUNT cRows, DBCOUNTITEM * pcRowsObtained, HROW * * prghRows ) { _DBErrorObj.ClearErrorInfo();
SCODE scResult = S_OK; BOOL fNotified = FALSE;
CheckCrowsArgs( cRows, pcRowsObtained );
if (_fForwardOnly && cRowsToSkip < 0) return _DBErrorObj.PostHResult(DB_E_CANTSCROLLBACKWARDS, IID_IRowset); if (_fForwardOnly && cRows < 0 ) return _DBErrorObj.PostHResult(DB_E_CANTFETCHBACKWARDS, IID_IRowset);
TRY { if (! _fHoldRows) _pRowBufs->CheckAllHrowsReleased();
CI_TBL_CHAPT chapt = _MapChapter(hChapter);
if ( !_pRowsetNotification.IsNull() && _pRowsetNotification->IsNotifyActive() ) { scResult = _pRowsetNotification->OnRowsetChange( this, DBREASON_ROWSET_FETCHPOSITIONCHANGE, DBEVENTPHASE_OKTODO, FALSE);
if ( S_FALSE == scResult ) THROW(CException(DB_E_CANCELED)); fNotified = TRUE; }
CRowSeekNext rowSeek( chapt, (LONG) cRowsToSkip );
scResult = _FetchRows(rowSeek, cRows, pcRowsObtained, prghRows);
if ( fNotified ) { if (SUCCEEDED(scResult)) { if ( *pcRowsObtained != 0 ) _pRowsetNotification->OnRowChange( this, *pcRowsObtained, *prghRows, DBREASON_ROW_ACTIVATE, DBEVENTPHASE_DIDEVENT, TRUE); _pRowsetNotification->OnRowsetChange( this, DBREASON_ROWSET_FETCHPOSITIONCHANGE, DBEVENTPHASE_DIDEVENT, TRUE); } } if (FAILED(scResult)) _DBErrorObj.PostHResult(scResult, IID_IRowset); } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowset); scResult = GetOleError(e); } END_CATCH;
if ( fNotified && FAILED(scResult) ) _pRowsetNotification->OnRowsetChange( this, DBREASON_ROWSET_FETCHPOSITIONCHANGE, DBEVENTPHASE_FAILEDTODO, TRUE);
Win4Assert( cRowsToSkip != 0 || DB_E_BADSTARTPOSITION != scResult ); return scResult; }
//
// IRowsetIdentity methods
//
SCODE CRowset::IsSameRow ( HROW hThisRow, HROW hThatRow ) { _DBErrorObj.ClearErrorInfo();
SCODE scResult = S_OK; TRY { CTableColumnSet *pRowBufferColumns; BYTE *pbSrc;
//
// Lookup the HROWs to validate them
//
_pRowBufs->Lookup( hThisRow, &pRowBufferColumns, (void **) &pbSrc );
_pRowBufs->Lookup( hThatRow, &pRowBufferColumns, (void **) &pbSrc );
if (hThisRow != hThatRow) scResult = S_FALSE;
} CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetIdentity); scResult = GetOleError(e); } END_CATCH;
return scResult; }
//
// IRowsetWatchAll methods
//
SCODE CRowset::Acknowledge ( ) { _DBErrorObj.ClearErrorInfo(); SCODE scResult = S_OK; TRY { // Just use Refresh to acknowledge the notification.
_rQuery.Refresh(); } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchAll); scResult = GetOleError(e); } END_CATCH;
return scResult; }
SCODE CRowset::Start ( ) { _DBErrorObj.ClearErrorInfo(); SCODE scResult = S_OK; TRY { _rQuery.StartWatching(_hCursor); } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchAll); scResult = GetOleError(e); } END_CATCH;
return scResult; }
SCODE CRowset::StopWatching ( ) { _DBErrorObj.ClearErrorInfo(); SCODE scResult = S_OK; TRY { _rQuery.StopWatching(_hCursor); } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchAll); scResult = GetOleError(e); } END_CATCH;
return scResult;
}
//
// IRowsetWatchRegion methods
//
SCODE CRowset::ChangeWatchMode ( HWATCHREGION hRegion, DBWATCHMODE mode) { _DBErrorObj.ClearErrorInfo();
if (hRegion == watchRegionInvalid) return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetWatchRegion);;
SCODE scResult = S_OK; TRY { _rQuery.SetWatchMode(&hRegion, mode); } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchRegion); scResult = GetOleError(e); } END_CATCH;
return scResult; }
SCODE CRowset::CreateWatchRegion ( DBWATCHMODE mode, HWATCHREGION* phRegion) { _DBErrorObj.ClearErrorInfo();
SCODE scResult = S_OK; *phRegion = watchRegionInvalid; TRY { _rQuery.SetWatchMode(phRegion, mode); } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchRegion); scResult = GetOleError(e); } END_CATCH;
return scResult; }
SCODE CRowset::DeleteWatchRegion ( HWATCHREGION hRegion) { _DBErrorObj.ClearErrorInfo();
if (hRegion == watchRegionInvalid) return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetWatchRegion);
SCODE scResult = S_OK; TRY { _rQuery.ShrinkWatchRegion (hRegion, 0, 0, 0); } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchRegion); scResult = GetOleError(e); } END_CATCH;
return scResult; }
SCODE CRowset::GetWatchRegionInfo ( HWATCHREGION hRegion, DBWATCHMODE * pMode, HCHAPTER * phChapter, DBBKMARK * pcbBookmark, BYTE ** ppBookmark, DBROWCOUNT * pcRows) { _DBErrorObj.ClearErrorInfo();
if (hRegion == watchRegionInvalid) return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetWatchRegion);;
SCODE scResult = S_OK; // test pointers and prepare for failure
*phChapter = 0; *pcbBookmark = 0; *ppBookmark = 0; *pcRows = 0;
TRY { CI_TBL_CHAPT chapter; CI_TBL_BMK bookmark;
_rQuery.GetWatchInfo( hRegion, pMode, &chapter, &bookmark, (DBCOUNTITEM *)pcRows);
if (chapter != 0) { *phChapter = (HCHAPTER)chapter; } if (bookmark != 0) { XArrayOLE<CI_TBL_BMK> pOutBookmark (1); *pcbBookmark = sizeof CI_TBL_BMK; memcpy ( pOutBookmark.GetPointer(), &bookmark, sizeof CI_TBL_BMK); *ppBookmark = (BYTE*) pOutBookmark.Acquire(); }
} CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchRegion); scResult = GetOleError(e); } END_CATCH;
return scResult; }
SCODE CRowset::ShrinkWatchRegion ( HWATCHREGION hRegion, HCHAPTER hChapter, DBBKMARK cbBookmark, BYTE * pBookmark, DBROWCOUNT cRows ) { _DBErrorObj.ClearErrorInfo();
if (hRegion == watchRegionInvalid) return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetWatchRegion);;
SCODE scResult = S_OK;
TRY {
CI_TBL_BMK bookmark = _MapBookmark(cbBookmark, pBookmark); CI_TBL_CHAPT chapter = _MapChapter(hChapter);
_rQuery.ShrinkWatchRegion ( hRegion, chapter, bookmark, (LONG) cRows); } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchRegion); scResult = GetOleError(e); } END_CATCH;
return scResult; }
SCODE CRowset::Refresh ( DBCOUNTITEM* pCount, DBROWWATCHCHANGE** ppRowChange ) { _DBErrorObj.ClearErrorInfo();
SCODE scResult = S_OK; TRY { // prepare the buffers
// fetch the script and
// a bunch of rows.
// If not all rows fit in
// the buffer, call again.
_rQuery.Refresh(); *pCount = 0; scResult = DB_S_TOOMANYCHANGES; } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetWatchRegion); scResult = GetOleError(e); } END_CATCH;
return scResult; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::GetStatus, public
//
// Synopsis: Return query status
//
// Arguments: [pdwStatus] -- pointer to where query status is returned
//
// Returns: SCODE error code
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::GetStatus( DWORD * pdwStatus ) { _DBErrorObj.ClearErrorInfo();
SCODE scResult = S_OK; TRY { *pdwStatus = 0;
_rQuery.GetQueryStatus( _hCursor, *pdwStatus ); } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetQueryStatus); scResult = GetOleError(e); } END_CATCH;
return scResult; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::GetStatusEx, public
//
// Synopsis: Return query status
//
// Arguments: [pdwStatus] - returns query status
// [pcFilteredDocuments] - # of documents filtered
// [pcDocumentsToFilter] - # of docsuments yet to filter
// [pdwRatioFinishedDenominator] - ratio finished denominator
// [pdwRatioFinishedNumerator] - ratio finished numerator
// [cbBmk] - # of bytes in pBmk
// [pBmk] - bookmark for piRowBmk
// [piRowBmk] - returns index of bookmark in table
// [pcRowsTotal] - current # of rows in table
//
// Returns: SCODE error code
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::GetStatusEx( DWORD * pdwStatus, DWORD * pcFilteredDocuments, DWORD * pcDocumentsToFilter, DBCOUNTITEM * pdwRatioFinishedDenominator, DBCOUNTITEM * pdwRatioFinishedNumerator, DBBKMARK cbBmk, const BYTE * pBmk, DBCOUNTITEM * piRowBmk, DBCOUNTITEM * pcRowsTotal ) { _DBErrorObj.ClearErrorInfo();
SCODE scResult = S_OK; TRY { *pdwStatus = 0;
CI_TBL_BMK bmk = WORKID_TBLFIRST;
if ( cbBmk != 0 ) bmk = _MapBookmark( cbBmk, pBmk ); _rQuery.GetQueryStatusEx( _hCursor, *pdwStatus, *pcFilteredDocuments, *pcDocumentsToFilter, *pdwRatioFinishedDenominator, *pdwRatioFinishedNumerator, bmk, *piRowBmk, *pcRowsTotal ); } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowsetQueryStatus); scResult = GetOleError(e); } END_CATCH;
return scResult; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::GetReferencedRowset, public
//
// Synopsis: Return the related rowset for a hierarchical query.
//
// Arguments: [iOrdinal] -- ordinal of column for bookmark
// [riid] -- IID of desired interface
// [ppReferencedRowset] -- interface pointer returned here
//
// Returns: SCODE error code
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::GetReferencedRowset( DBORDINAL iOrdinal, REFIID riid, IUnknown ** ppReferencedRowset ) /*const*/ { _DBErrorObj.ClearErrorInfo();
if (0 == ppReferencedRowset) return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetInfo);
*ppReferencedRowset = 0;
if ( iOrdinal > _ColumnsInfo.GetColumnCount() || (0 == _pRelatedRowset && 0 == iOrdinal && _fForwardOnly)) return _DBErrorObj.PostHResult(DB_E_BADORDINAL, IID_IRowsetInfo);
if ( 0 == _pRelatedRowset && 0 != iOrdinal ) return _DBErrorObj.PostHResult(DB_E_NOTAREFERENCECOLUMN, IID_IRowsetInfo);
//
// If it's the bookmark column, it's like a QI on this rowset.
//
if (0 == iOrdinal) return QueryInterface( riid, (void **)ppReferencedRowset );
//
// Make sure the column is a valid chapter column.
//
const DBCOLUMNINFO & rColInfo = _ColumnsInfo.Get1ColumnInfo( (ULONG) iOrdinal );
if ( (rColInfo.dwFlags & DBCOLUMNFLAGS_ISBOOKMARK) == 0 || (rColInfo.dwFlags & DBCOLUMNFLAGS_ISROWID) != 0 ) return _DBErrorObj.PostHResult(DB_E_NOTAREFERENCECOLUMN, IID_IRowsetInfo);
return _pRelatedRowset->QueryInterface( riid, (void **)ppReferencedRowset ); }
//+---------------------------------------------------------------------------
//
// Member: CRowset::RestartPosition, public
//
// Synopsis: Set up CRowset so next GetNextRows will restart from beginning
//
// Arguments: [hChapter] -- chapter which should restart
//
// Returns: SCODE error code
//
// Notes:
//
// History: 16-Apr-97 emilyb wrote
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::RestartPosition( HCHAPTER hChapter ) { _DBErrorObj.ClearErrorInfo();
SCODE scResult = S_OK; BOOL fNotified = FALSE;
TRY { if (! _fHoldRows) _pRowBufs->CheckAllHrowsReleased();
CI_TBL_CHAPT chapter = _MapChapter(hChapter); // is chapter valid?
if ( !_pRowsetNotification.IsNull() && _pRowsetNotification->IsNotifyActive() ) { scResult = _pRowsetNotification->OnRowsetChange( this, DBREASON_ROWSET_FETCHPOSITIONCHANGE, DBEVENTPHASE_OKTODO, FALSE);
if ( S_FALSE == scResult ) THROW(CException(DB_E_CANCELED)); fNotified = TRUE; }
_rQuery.RestartPosition(_hCursor, chapter);
if ( fNotified ) _pRowsetNotification->OnRowsetChange( this, DBREASON_ROWSET_FETCHPOSITIONCHANGE, DBEVENTPHASE_DIDEVENT, TRUE); } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IRowset); scResult = GetOleError(e);
if (E_NOTIMPL == scResult) { scResult = DB_E_CANNOTRESTART; } } END_CATCH;
if ( fNotified && FAILED(scResult) ) _pRowsetNotification->OnRowsetChange( this, DBREASON_ROWSET_FETCHPOSITIONCHANGE, DBEVENTPHASE_FAILEDTODO, TRUE); return scResult; }
//
// IDbAsynchStatus methods
//
//+---------------------------------------------------------------------------
//
// Member: CRowset::Abort, public
//
// Synopsis: Cancels an asynchronously executing operation.
//
// Arguments: [hChapter] -- chapter which should restart
// [ulOperation] -- operation for which status is being requested
//
// Returns: SCODE error code
//
// Notes:
//
// History: 09 Feb 1998 AlanW Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::Abort( HCHAPTER hChapter, ULONG ulOperation ) { _DBErrorObj.ClearErrorInfo();
SCODE scResult = S_OK;
if ( DBASYNCHOP_OPEN != ulOperation ) { return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IDBAsynchStatus); }
TRANSLATE_EXCEPTIONS; TRY { CI_TBL_CHAPT chapter = _MapChapter(hChapter); // is chapter valid?
_rQuery.StopAsynch(_hCursor); } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IDBAsynchStatus); scResult = GetOleError(e);
if (E_NOTIMPL == scResult) { scResult = DB_E_CANTCANCEL; _DBErrorObj.PostHResult(scResult, IID_IDBAsynchStatus); } } END_CATCH; UNTRANSLATE_EXCEPTIONS;
return scResult; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::GetStatus, public
//
// Synopsis: Returns the status of an asynchronously executing operation.
//
// Arguments: [hChapter] -- chapter which should restart
// [ulOperation] -- operation for which status is being requested
//
// Returns: SCODE error code
//
// Notes:
//
// History: 09 Feb 1998 AlanW Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::GetStatus( HCHAPTER hChapter, DBASYNCHOP ulOperation, DBCOUNTITEM * pulProgress, DBCOUNTITEM * pulProgressMax, DBASYNCHPHASE * pulAsynchPhase, LPOLESTR * ppwszStatusText ) { _DBErrorObj.ClearErrorInfo();
SCODE scResult = S_OK;
if ( DBASYNCHOP_OPEN != ulOperation ) { return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IDBAsynchStatus); }
TRANSLATE_EXCEPTIONS; TRY { // NOTE: we don't support getting the status of chapters
// independently.
// CI_TBL_CHAPT chapter = _MapChapter(hChapter); // is chapter valid?
if (DB_NULL_HCHAPTER != hChapter) THROW( CException( DB_E_BADCHAPTER ));
DBCOUNTITEM ulNumerator = 0; DBCOUNTITEM ulDenominator = 0; DBCOUNTITEM cRows; BOOL fNewRows;
_rQuery.RatioFinished( _hCursor, ulDenominator, ulNumerator, cRows, fNewRows );
if (pulProgress) *pulProgress = ulNumerator; if (pulProgressMax) *pulProgressMax = ulDenominator; if (pulAsynchPhase) *pulAsynchPhase = (ulDenominator == ulNumerator) ? DBASYNCHPHASE_COMPLETE : DBASYNCHPHASE_POPULATION; if (ppwszStatusText) *ppwszStatusText = 0;
#if CIDBG
if ( _fForwardOnly ) Win4Assert( ulDenominator == ulNumerator ); else Win4Assert( ulDenominator >= ulNumerator ); #endif // CIDBG
} CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IDBAsynchStatus); scResult = GetOleError(e); } END_CATCH; UNTRANSLATE_EXCEPTIONS;
return scResult; }
//+---------------------------------------------------------------------------
//
// Member: CRowset::GetSpecification, public
//
// Synopsis: Return the session or command object used to create this rowset
//
// Arguments: [hChapter] -- chapter which should restart
//
// Notes:
//
// History: 01-28-98 danleg Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::GetSpecification( REFIID riid, IUnknown ** ppvSpecification ) { _DBErrorObj.ClearErrorInfo();
if ( 0 == ppvSpecification ) return _DBErrorObj.PostHResult( E_INVALIDARG, IID_IRowsetInfo ); SCODE sc = S_OK; TRANSLATE_EXCEPTIONS; TRY { *ppvSpecification = 0;
if ( _xUnkCreator.IsNull() ) return S_FALSE;
sc = _xUnkCreator->QueryInterface( riid, (void ** )ppvSpecification ); if ( FAILED(sc) ) THROW( CException(sc) );
} CATCH( CException, e ) { sc = _DBErrorObj.PostHResult( e, IID_IRowsetInfo ); } END_CATCH; UNTRANSLATE_EXCEPTIONS; return sc; }
//
// IServiceProperties methods
//
//+---------------------------------------------------------------------------
//
// Method: CRowset::GetPropertyInfo, public
//
// Synopsis: Get rowset properties
//
// Arguments: [cPropertySetIDs] - number of desired properties or 0
// [rgPropertySetIDs] - array of desired properties or NULL
// [pcPropertySets] - number of property sets returned
// [prgPropertySets] - array of returned property sets
// [ppwszDesc] - if non-zero, property descriptions are
// returneed
//
// History: 16 Nov 95 AlanW Created
//
//----------------------------------------------------------------------------
SCODE CRowset::GetPropertyInfo( const ULONG cPropertySetIDs, const DBPROPIDSET rgPropertySetIDs[], ULONG * pcPropertySets, DBPROPINFOSET ** prgPropertySets, WCHAR ** ppwszDesc) { _DBErrorObj.ClearErrorInfo();
if ( (0 != cPropertySetIDs && 0 == rgPropertySetIDs) || 0 == pcPropertySets || 0 == prgPropertySets ) { if (pcPropertySets) *pcPropertySets = 0; if (prgPropertySets) *prgPropertySets = 0; return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IServiceProperties); }
SCODE sc = S_OK; *pcPropertySets = 0; *prgPropertySets = 0; if (ppwszDesc) *ppwszDesc = 0;
TRANSLATE_EXCEPTIONS; TRY { sc = _PropInfo.GetPropertyInfo( cPropertySetIDs, rgPropertySetIDs, pcPropertySets, prgPropertySets, ppwszDesc );
// Don't PostHResult here -- it's a good chance it's a scope
// property that we're expecting to fail. Spare the expense.
// The child object will post the error for us.
} CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IServiceProperties); sc = GetOleError(e);
} END_CATCH; UNTRANSLATE_EXCEPTIONS;
return sc; }
//+---------------------------------------------------------------------------
//
// Method: CRowset::SetRequestedProperties, public
//
// Synopsis: Set rowset properties via IServiceProperties (not supported)
//
// Arguments: [cPropertySets] - number of property sets
// [rgProperties] - array of property sets to be set
//
// History: 16 Nov 95 AlanW Created
//
//----------------------------------------------------------------------------
SCODE CRowset::SetRequestedProperties( ULONG cPropertySets, DBPROPSET rgPropertySets[]) { _DBErrorObj.ClearErrorInfo();
if ( 0 != cPropertySets && 0 == rgPropertySets) return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IServiceProperties);;
return _DBErrorObj.PostHResult(E_NOTIMPL, IID_IServiceProperties);; }
//+---------------------------------------------------------------------------
//
// Method: CRowset::SetSuppliedProperties, public
//
// Synopsis: Set rowset properties via IServiceProperties (not supported)
//
// Arguments: [cPropertySets] - number of property sets
// [rgProperties] - array of property sets to be set
//
// History: 16 Nov 95 AlanW Created
//
//----------------------------------------------------------------------------
SCODE CRowset::SetSuppliedProperties( ULONG cPropertySets, DBPROPSET rgPropertySets[]) { _DBErrorObj.ClearErrorInfo();
if ( 0 != cPropertySets && 0 == rgPropertySets) return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IServiceProperties);;
return _DBErrorObj.PostHResult(E_NOTIMPL, IID_IServiceProperties);; }
//+---------------------------------------------------------------------------
//
// Method: CRowset::AddRefChapter, public
//
// Synopsis: Increment the ref. count to a chapter
//
// Arguments: [hChapter] - handle to chapter
// [pcRefCount] - pointer to chapter ref. count
//
// Notes: Chapter references are obtained via an accessor from the
// parent rowset, but they are addref'ed in the child rowset.
//
// History: 15 Mar 99 AlanW Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::AddRefChapter( HCHAPTER hChapter, ULONG * pcRefCount ) { tbDebugOut(( DEB_TRACE, "CRowset::AddRefChapter called!\n" )); _DBErrorObj.ClearErrorInfo();
if (0 == _pChapterRowbufs) return _DBErrorObj.PostHResult(E_FAIL, IID_IChapteredRowset);
if (DB_NULL_HCHAPTER == hChapter) return _DBErrorObj.PostHResult(DB_E_BADCHAPTER, IID_IChapteredRowset);
SCODE scResult = S_OK;
TRANSLATE_EXCEPTIONS; TRY { _pChapterRowbufs->AddRefChapter(hChapter, pcRefCount); } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IChapteredRowset); scResult = GetOleError(e); } END_CATCH; UNTRANSLATE_EXCEPTIONS;
return scResult; }
//+---------------------------------------------------------------------------
//
// Method: CRowset::ReleaseChapter, public
//
// Synopsis: Decrement the ref. count to a chapter
//
// Arguments: [hChapter] - handle to chapter
// [pcRefCount] - pointer to chapter ref. count
//
// Notes: Chapter references are obtained via an accessor from the
// parent rowset, but they are released in the child rowset.
//
// History: 15 Mar 99 AlanW Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowset::ReleaseChapter( HCHAPTER hChapter, ULONG * pcRefCount ) { tbDebugOut(( DEB_TRACE, "CRowset::ReleaseChapter called!\n" )); _DBErrorObj.ClearErrorInfo();
if (0 == _pChapterRowbufs) return _DBErrorObj.PostHResult(E_FAIL, IID_IChapteredRowset);
if (DB_NULL_HCHAPTER == hChapter) return _DBErrorObj.PostHResult(DB_E_BADCHAPTER, IID_IChapteredRowset);
SCODE scResult = S_OK; TRANSLATE_EXCEPTIONS; TRY { _pChapterRowbufs->ReleaseChapter(hChapter, pcRefCount); } CATCH( CException, e ) { _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IChapteredRowset); scResult = GetOleError(e); } END_CATCH; UNTRANSLATE_EXCEPTIONS;
return scResult; }
STDMETHODIMP CRowset::Stop( ) { SCODE scResult = S_OK; TRY { _rQuery.StopAsynch(_hCursor); } CATCH( CException, e ) { scResult = GetOleError(e); } END_CATCH;
return scResult; }
|