//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1995 - 2000 // // File: PosCache.cxx // // Contents: Positionable cache // // Classes: CMiniPositionableCache // // History: 05-Jun-95 KyleP Created // 14-JAN-97 KrishnaN Undefined CI_INETSRV and related changes // 29-Mar-2000 KLam Fixed Bookmarks // //---------------------------------------------------------------------------- #include #pragma hdrstop #include "poscache.hxx" //+--------------------------------------------------------------------------- // // Member: CMiniPositionableCache::CMiniPositionableCache, public // // Synopsis: Builds bindings to fetch bookmark. // // Arguments: [Index] -- Identifier. Not used internally. // [pRowsetScroll] -- Rowset used to fill cache. // [cBindings] -- Size of [pBindings]. // [pBindings] -- Default binding. // [cbMaxLen] -- Max length of data fetched via [pBindings] // [iColumnBookmark] -- Ordinal of column containing bookmark. // [cbBookmark] -- Size of bookmark // // History: 05-Jun-95 KyleP Created. // 06-Jan-2000 KLam Fixed bindings // //---------------------------------------------------------------------------- CMiniPositionableCache::CMiniPositionableCache( int Index, IRowsetScroll * pRowsetScroll, unsigned cBindings, DBBINDING * pBindings, unsigned cbMaxLen, DBORDINAL iColumnBookmark, DBBKMARK cbBookmark ) : PMiniRowCache( Index, pRowsetScroll, cBindings, pBindings, cbMaxLen ), _pRowsetScroll( pRowsetScroll ), _fUsingBookmark( FALSE ), _haccBookmark( (HACCESSOR)0xFFFFFFFF ), _pbBookmark( (unsigned) ( sizeof(DBBKMARK) + cbBookmark + 1 )), _pbBookmarkSeek( (unsigned) (sizeof(DBBKMARK) + cbBookmark + 1 )), _hrowPrev( DB_NULL_HROW ) { if ( iColumnBookmark != -1 ) { _fUsingBookmark = TRUE; // // Setup accessor for bookmark. // DBBINDING bindBmk; RtlZeroMemory(&bindBmk, sizeof bindBmk); bindBmk.iOrdinal = iColumnBookmark; bindBmk.obValue = sizeof(DBLENGTH); bindBmk.obLength = 0; bindBmk.dwPart = DBPART_VALUE | DBPART_LENGTH; bindBmk.cbMaxLen = _pbBookmark.Count() - sizeof(DBLENGTH); bindBmk.wType = DBTYPE_BYTES; IAccessor * pia = 0; SCODE sc = _pRowsetScroll->QueryInterface( IID_IAccessor, (void **)&pia ); if (SUCCEEDED( sc )) { sc = pia->CreateAccessor( DBACCESSOR_ROWDATA, 1, &bindBmk, 0, &_haccBookmark, 0); pia->Release(); } if ( FAILED(sc) ) { vqDebugOut(( DEB_ERROR, "CMiniPositionableCache: CreateAccessor returned 0x%x\n", sc )); THROW( CException( sc ) ); } } // // Start with bookmark positioned at beginning of rowset (DBBMK_FIRST) // *(DBBKMARK *)_pbBookmark.GetPointer() = sizeof(BYTE); _pbBookmark[sizeof(DBBKMARK)] = DBBMK_FIRST; _oBookmark = 0; *(DBBKMARK *)_pbBookmarkSeek.GetPointer() = sizeof(BYTE); _pbBookmarkSeek[sizeof(DBBKMARK)] = DBBMK_FIRST; _xpbPrevRow.Set( new BYTE [_cbRow] ); Next(); } //+--------------------------------------------------------------------------- // // Member: CMiniPositionableCache::~CMiniPositionableCache, public // // Synopsis: Destructor // // History: 05-Jun-95 KyleP Created. // //---------------------------------------------------------------------------- CMiniPositionableCache::~CMiniPositionableCache() { if ( _haccBookmark != (HACCESSOR)0xFFFFFFFF ) { IAccessor * pia = 0; _pRowsetScroll->QueryInterface( IID_IAccessor, (void **)&pia ); Win4Assert(pia && "No Accessor!"); pia->ReleaseAccessor( _haccBookmark, 0 ); pia->Release(); } } //+--------------------------------------------------------------------------- // // Member: CMiniPositionableCache::Next, public // // Synopsis: Moves to next row // // Returns: Move status // // History: 05-Jun-95 KyleP Created. // //---------------------------------------------------------------------------- PMiniRowCache::ENext CMiniPositionableCache::Next( int iDir /* = 1 */ ) { // // If we had a row in cache, Just advance to it. Otherwise // fetch more rows from table. // _ihrow++; if ( _ihrow >= _chrow ) { Win4Assert( iDir ); iDir = iDir > 0 ? 1 : -1 ; // // Fetch more rows from table. // HROW * phrow = _ahrow.GetPointer(); SCODE sc = _pRowsetScroll->GetRowsAt( 0, // Watch region handle 0, // Chapter *(DBBKMARK *)_pbBookmark.GetPointer(), // cbBookmark _pbBookmark.GetPointer() + sizeof(DBBKMARK), // pbBookmark _oBookmark, // Offset from bookmark _ahrow.Count() * iDir, // Rows requested &_chrow, // Rows received &phrow ); // HROWs stored here Win4Assert( DB_E_BADSTARTPOSITION != sc ); vqDebugOut(( DEB_ITRACE, "Fetched %d from %d\n", _chrow, _Index )); if ( FAILED(sc) ) { vqDebugOut(( DEB_ERROR, "CMiniPositionableCache: Error 0x%x from GetRowsAt\n", sc )); _chrow = 0; THROW( CException( sc ) ); } else if ( 0 == _chrow && sc != DB_S_ENDOFROWSET ) { return( PMiniRowCache::NotNow ); } if ( _fUsingBookmark && _chrow > 0 ) { // // Update current bookmark to last row fetched. // SCODE sc = _pRowsetScroll->GetData( _ahrow[(unsigned) (_chrow-1)], _haccBookmark, _pbBookmark.GetPointer() ); if ( FAILED(sc) ) { vqDebugOut(( DEB_ERROR, "Error 0x%x fetching bookmark\n", sc )); THROW( CException( sc ) ); } _oBookmark = 1; } else _oBookmark += _chrow; _ihrow = 0; } if( IsAtEnd() ) { *(DBBKMARK *)_pbBookmark.GetPointer() = sizeof(BYTE); _pbBookmark[sizeof(DBBKMARK)] = DBBMK_LAST; return CMiniPositionableCache::EndOfRows; } LoadData(); return CMiniPositionableCache::Ok; } //+--------------------------------------------------------------------------- // // Member: CMiniPositionableCache::LoadPrevRowData, public // // Synopsis: Load the previous row data from the current top // position into _hrowPrev and _xpbPrevRow // // Returns: status // // History: 12-Sep-98 VikasMan Created // // Notes: The positioning of the cursor does not change in this call. // _hrwoPrev is set to DB_NULL_HROW if there is no previous row // //---------------------------------------------------------------------------- PMiniRowCache::ENext CMiniPositionableCache::LoadPrevRowData() { DBCOUNTITEM chrow = 0; if ( _hrowPrev != DB_NULL_HROW ) { _pRowsetScroll->ReleaseRows( 1, &_hrowPrev, 0, 0, 0 ); _hrowPrev = DB_NULL_HROW; } HROW * phrowPrev = &_hrowPrev; SCODE sc = _pRowsetScroll->GetRowsAt( 0, // Watch region handle 0, // Chapter *(DBBKMARK *)_pbBookmark.GetPointer(), // cbBookmark _pbBookmark.GetPointer() + sizeof(DBBKMARK), // pbBookmark 0 - _chrow, // Offset from bookmark 1, // Rows requested &chrow, // Rows received &phrowPrev ); // HROWs stored here Win4Assert( DB_E_BADSTARTPOSITION != sc ); vqDebugOut(( DEB_ITRACE, "Fetched %d from %d\n", chrow, _Index )); if ( FAILED(sc) ) { vqDebugOut(( DEB_ERROR, "CMiniPositionableCache: Error 0x%x from GetRowsAt\n", sc )); _hrowPrev = DB_NULL_HROW; THROW( CException( sc ) ); } else if ( 0 == chrow ) { return ( sc == DB_S_ENDOFROWSET ? PMiniRowCache::EndOfRows : PMiniRowCache::NotNow ); } if ( 1 == chrow ) { Win4Assert( _hrowPrev != DB_NULL_HROW ); // Load Data SCODE sc = _pRowset->GetData( _hrowPrev, _hacc, _xpbPrevRow.GetPointer() ); if ( FAILED(sc) ) { vqDebugOut(( DEB_ERROR, "PMiniRowCache: GetData returned 0x%x\n", sc )); THROW( CException( E_FAIL ) ); } } return CMiniPositionableCache::Ok; } //+--------------------------------------------------------------------------- // // Member: CMiniPositionableCache::MovePrev, public // // Synopsis: Move to the previous row // // Returns: status // // History: 12-Sep-98 VikasMan Created // // Notes: This function uses _hrowPrev to move to previous row. Use // LoadPrevRowData to fill up _hrowPrev and then call this function. // // //---------------------------------------------------------------------------- PMiniRowCache::ENext CMiniPositionableCache::MovePrev() { if ( _ihrow > 0 ) { _ihrow--; } else if ( _hrowPrev != DB_NULL_HROW ) { if ( _chrow > 0 ) { _pRowsetScroll->ReleaseRows( 1, &_ahrow[(unsigned)(_chrow - 1)], 0, 0, 0 ); RtlMoveMemory( &_ahrow[1], &_ahrow[0], ( _chrow - 1 ) * sizeof( HROW ) ); } else { SetCacheSize( _chrow = 1 ); } _ahrow[0] = _hrowPrev; _hrowPrev = DB_NULL_HROW; RtlCopyMemory( _pbRow, _xpbPrevRow.GetPointer(), _cbRow ); if ( _fUsingBookmark ) { // // Update current bookmark to last row fetched. // SCODE sc = _pRowsetScroll->GetData( _ahrow[(unsigned)(_chrow-1)], _haccBookmark, _pbBookmark.GetPointer() ); if ( FAILED(sc) ) { vqDebugOut(( DEB_ERROR, "Error 0x%x fetching bookmark\n", sc )); THROW( CException( sc ) ); } _oBookmark = 1; } } return CMiniPositionableCache::Ok; } //+--------------------------------------------------------------------------- // // Member: CMiniPositionableCache::Seek, public // // Synopsis: Seek forward from current position. // // Arguments: [lRows] -- Rows to move from last seek position. // // Returns: Move status // // History: 05-Jun-95 KyleP Created. // //---------------------------------------------------------------------------- PMiniRowCache::ENext CMiniPositionableCache::Seek( DBROWOFFSET lRows ) { FlushCache(); memcpy( _pbBookmark.GetPointer(), _pbBookmarkSeek.GetPointer(), _pbBookmark.Count() ); _oBookmark = lRows; vqDebugOut(( DEB_ITRACE, "%d: Seek %d\n", Index(), lRows )); return Next(); } //+--------------------------------------------------------------------------- // // Member: CMiniPositionableCache::Seek, public // // Synopsis: Seek to specified bookmark. // // Arguments: [cbBookmark] -- Size of [pbBookmark] // [pbBookmark] -- Bookmark // // Returns: Move status // // History: 05-Jun-95 KyleP Created. // //---------------------------------------------------------------------------- PMiniRowCache::ENext CMiniPositionableCache::Seek( DBBKMARK cbBookmark, BYTE const * pbBookmark ) { Win4Assert( _fUsingBookmark || (cbBookmark == 1 && (*pbBookmark == DBBMK_FIRST || *pbBookmark == DBBMK_LAST) ) ); FlushCache(); #if CIDBG == 1 if ( cbBookmark == 4 ) vqDebugOut(( DEB_ITRACE, "%d: Seek 0x%x\n", Index(), *(ULONG UNALIGNED *)pbBookmark )); #endif // // Set up bookmark. // *(DBBKMARK *)_pbBookmark.GetPointer() = cbBookmark; memcpy( _pbBookmark.GetPointer() + sizeof(DBBKMARK), pbBookmark, (unsigned) cbBookmark ); *(DBBKMARK *)_pbBookmarkSeek.GetPointer() = cbBookmark; memcpy( _pbBookmarkSeek.GetPointer() + sizeof(DBBKMARK), pbBookmark, (unsigned) cbBookmark ); _oBookmark = 0; return Next(); } //+--------------------------------------------------------------------------- // // Member: CMiniPositionableCache::Seek, public // // Synopsis: Seek to specified approximate position. // // Arguments: [ulNumerator] -- Numerator. // [ulDenominator] -- Denominator. // // Returns: Move status // // History: 05-Jun-95 KyleP Created. // //---------------------------------------------------------------------------- PMiniRowCache::ENext CMiniPositionableCache::Seek( DBCOUNTITEM ulNumerator, DBCOUNTITEM ulDenominator ) { Win4Assert( _fUsingBookmark ); FlushCache(); vqDebugOut(( DEB_ITRACE, "%d: Seek %u/%u through.\n", Index(), ulNumerator, ulDenominator )); HROW * phrow = _ahrow.GetPointer(); SCODE sc = _pRowsetScroll->GetRowsAtRatio( 0, // Watch region handle 0, // Chapter ulNumerator, ulDenominator, _ahrow.Count(), // Rows requested &_chrow, // Rows received &phrow ); // HROWs stored here vqDebugOut(( DEB_ITRACE, "Fetched %d from %d\n", _chrow, _Index )); if ( FAILED(sc) ) { vqDebugOut(( DEB_ERROR, "CMiniPositionableCache: Error 0x%x from GetRowsAtRatio\n", sc )); _chrow = 0; THROW( CException( sc ) ); } else if ( 0 == _chrow && sc != DB_S_ENDOFROWSET ) { return( PMiniRowCache::NotNow ); } if ( _chrow > 0 ) { // // Update current bookmark to last row fetched. // SCODE sc = _pRowsetScroll->GetData( _ahrow[(unsigned)(_chrow-1)], _haccBookmark, _pbBookmark.GetPointer() ); if ( FAILED(sc) ) { vqDebugOut(( DEB_ERROR, "Error 0x%x fetching bookmark\n", sc )); THROW( CException( sc ) ); } memcpy( _pbBookmarkSeek.GetPointer(), _pbBookmark.GetPointer(), _pbBookmark.Count() ); _oBookmark = 1; } _ihrow = 0; if( IsAtEnd() ) { return CMiniPositionableCache::EndOfRows; } LoadData(); return CMiniPositionableCache::Ok; } //+--------------------------------------------------------------------------- // // Member: CMiniPositionableCache::FlushCache, public // // Synopsis: Clear the cache. // // History: 12-Sep-98 VikasMan Created // //---------------------------------------------------------------------------- void CMiniPositionableCache::FlushCache() { if ( _hrowPrev != DB_NULL_HROW ) { _pRowsetScroll->ReleaseRows( 1, &_hrowPrev, 0, 0, 0 ); _hrowPrev = DB_NULL_HROW; } PMiniRowCache::FlushCache(); }