//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1994 - 2000. // // File: regtrans.cxx // // Contents: Watch Region Transformer // // Classes: CRegionTransformer // // History: 20-Jul-95 BartoszM Created // //-------------------------------------------------------------------------- #include #pragma hdrstop #include #include #include "tabledbg.hxx" #include "regtrans.hxx" #include "tblwindo.hxx" #include "tputget.hxx" BOOL CRegionTransformer::Validate() { tbDebugOut(( DEB_REGTRANS, "CRegionTransformer::Validate\n" )); DumpState(); _iFetch = _iFetchBmk + _offFetch; if (_cFetch < 0) { // for negative row count, we swap the start // of the fetch region with its end _iFetch += _cFetch + 1; _cFetch = - _cFetch; } if (_pRegion != 0) { _cWatch = _pRegion->RowCount(); if (_iFetch < _iWatch) { _isExtendBackward = TRUE; } if (_iFetch + _cFetch > _iWatch + _cWatch) { _isExtendForward = TRUE; } if ( !_pRegion->IsInit() ) { // // BootStrap - creating a watch region for the first time. // _iWatchNew = _iFetch; _cWatchNew = _cFetch; _isContiguous = FALSE; return TRUE; } else if (_pRegion->Mode() & DBWATCHMODE_EXTEND) { return ValidateExtend(); } else if (_pRegion->Mode() & DBWATCHMODE_MOVE) { return ValidateMove(); } else { return FALSE; } } return TRUE; } BOOL CRegionTransformer::ValidateMove () { tbDebugOut(( DEB_REGTRANS, "CRegionTransformer::ValidateMove\n" )); Win4Assert( 0 != _pRegion ); if (_isExtendForward && _isExtendBackward) return FALSE; _cWatchNew = _cWatch; if (_isExtendForward) { _iWatchNew = _iFetch + _cFetch - _cWatchNew; } else { _iWatchNew = _iFetch; } // For the new region to be contiguous with the // old region we require that the fetch bookmark // be within the old region and that there be overlap // between the old and the new regions. In any other case // the client cannot be sure of contiguity and we are // free to skip any buckets between the two regions. // Is the Fetch Bookmark inside the watch region? if (_iFetchBmk >= _iWatch && _iFetchBmk < _iWatch + _cWatch) { // Do the regions overlap? if ( _isExtendBackward && _iWatchNew + _cWatchNew > _iWatch || !_isExtendBackward && _iWatchNew < _iWatch + _cWatch ) { _isContiguous = TRUE; } } DumpState(); if (!_isContiguous && _cFetch != _cWatchNew) return FALSE; // if ( !_isContiguous && _cFetch > _cWatchNew ) // return FALSE; return TRUE; } BOOL CRegionTransformer::ValidateExtend () { tbDebugOut(( DEB_REGTRANS, "CRegionTransformer::ValidateExtend\n" )); _iWatchNew = _iWatch; _cWatchNew = _cWatch; if (_isExtendBackward) { // is there a gap? if (_iFetch + _cFetch < _iWatch) return FALSE; _iWatchNew = _iFetch; _cWatchNew += _iWatch - _iFetch; } if (_isExtendForward) { // is there a gap? if (_iFetch > _iWatch + _cWatch) return FALSE; _cWatchNew += _iFetch + _cFetch - (_iWatch + _cWatch); } _isContiguous = TRUE; return TRUE; } void CRegionTransformer::Transform (CTableSegList& segList, CWatchList& watchList) { tbDebugOut(( DEB_REGTRANS, "++++++ CRegionTransformer::Transform - Entering \n" )); if (!_isContiguous) { tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME, "Not Contiguous\n" )); // Delete old region, create new region watchList.ShrinkRegionToZero (_pRegion->Handle()); watchList.BuildRegion ( _pRegion->Handle(), _pSegmentLowFetch, 0, // NEWFEATURE: no watch regions for chapters ((CTableWindow*)_pSegmentLowFetch)->GetBookMarkAt((ULONG)_offLowFetchInSegment), (LONG) _cWatchNew ); return; } tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME, " Chapter=0x%X \tBookMark=0x%X \tcRows=%d \tSegment=0x%X \n", _pRegion->Chapter(), _pRegion->Bookmark(), _pRegion->RowCount(), _pRegion->Segment() )); DumpState(); Win4Assert( _iWatch >= 0 && _iWatchNew >= 0 ); CTableSegment* pSegment; if (_isExtendBackward) { pSegment = _pSegmentLowFetch; } else { pSegment = _pRegion->Segment(); } // Create a state machine that will transform // watch regions window by window CDoubleTableSegIter iter (pSegment); enum State { stStart, stInOld, stInNew, stInBoth, stEnd }; State state = stStart; CTableWindow* pWindow = iter.GetWindow(); DBROWCOUNT cRowsInWindow = pWindow->RowCount(); BOOL isLast = segList.IsLast(iter); DBROWCOUNT offset = 0; DBROWCOUNT cWatchLeft = _cWatchNew; Win4Assert( _cWatchNew >= _cWatch ); DBROWCOUNT iBeginInWindow = 0; tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME, "Doing State Change\n" )); do { BOOL fAdvance = FALSE; switch (state) { case stStart: tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME, "stStart\n" )); if (HasNewRegion( offset, cRowsInWindow)) { iBeginInWindow = _iWatchNew - offset; // NEWFEATURE no watches for chaptered tables _pRegion->Set (0, pWindow->GetBookMarkAt((ULONG) iBeginInWindow), (LONG) _cWatchNew); _pRegion->SetSegment (pWindow); //Win4Assert( pWindow->HasWatch( _pRegion->Handle() ) ); state = stInNew; } if (HasOldRegion( (long) offset, (long) cRowsInWindow)) { if (state == stInNew) state = stInBoth; else state = stInOld; } break; case stInOld: tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME, "stInOld\n" )); if (HasNewRegion( offset, cRowsInWindow)) { iBeginInWindow = _iWatchNew - offset; // NEWFEATURE no watches for chaptered tables _pRegion->Set (0, pWindow->GetBookMarkAt((ULONG)iBeginInWindow), (LONG)_cWatchNew); _pRegion->SetSegment (pWindow); Win4Assert( pWindow->HasWatch( _pRegion->Handle() ) ); state = stInBoth; } else if (HasEndOldRegion(offset, cRowsInWindow)) { pWindow->DeleteWatch (_pRegion->Handle()); state = stEnd; } else { pWindow->DeleteWatch (_pRegion->Handle()); fAdvance = !isLast; } break; case stInNew: tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME, "stInNew\n" )); if (HasOldRegion(offset, cRowsInWindow)) { state = stInBoth; } else if (HasEndNewRegion(offset, cRowsInWindow)) { cWatchLeft -= pWindow->AddWatch ( _pRegion->Handle(), (LONG) iBeginInWindow, (LONG) cWatchLeft, isLast ); // in all subsequent windows the watch // will start at offset zero iBeginInWindow = 0; state = stEnd; } else { Win4Assert( cWatchLeft > 0 ); cWatchLeft -= pWindow->AddWatch ( _pRegion->Handle(), (LONG) iBeginInWindow, (LONG) cWatchLeft, isLast ); // in all subsequent windows the watch // will start at offset zero iBeginInWindow = 0; fAdvance = !isLast; } break; case stInBoth: tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME, "stInBoth\n" )); cWatchLeft -= pWindow->ModifyWatch ( _pRegion->Handle(), (LONG) iBeginInWindow, (LONG) cWatchLeft, isLast ); if ( !isLast ) { // in all subsequent windows the watch // will start at offset zero iBeginInWindow = 0; fAdvance = TRUE; if (HasEndNewRegion(offset, cRowsInWindow)) { state = stInOld; } else { Win4Assert( cWatchLeft > 0 || isLast ); } if (HasEndOldRegion(offset, cRowsInWindow)) { if (state == stInOld) { fAdvance = FALSE; state = stEnd; } else { state = stInNew; } } } else { state = stEnd; } break; case stEnd: break; } if ( fAdvance) { tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME, "--- BEFORE ADVANCING offset=%d cRowsInWindow=%d isLast=%d\n", offset, cRowsInWindow, isLast )); Win4Assert (!isLast); offset += cRowsInWindow; segList.Advance(iter); Win4Assert( iter.GetSegment()->IsWindow() ); pWindow = iter.GetWindow(); cRowsInWindow = pWindow->RowCount(); isLast = segList.IsLast(iter); tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME, "--- AFTER ADVANCING offset=%d cRowsInWindow=%d isLast=%d\n", offset, cRowsInWindow, isLast )); } } while ( state != stEnd && !segList.AtEnd(iter) ); tbDebugOut(( DEB_REGTRANS, "------ CRegionTransformer::Transform - Leaving \n" )); tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME, " Chapter=0x%X \tBookMark=0x%X \tcRows=%d \tSegment=0x%X \n", _pRegion->Chapter(), _pRegion->Bookmark(), _pRegion->RowCount(), _pRegion->Segment() )); DumpState(); } //+--------------------------------------------------------------------------- // // Function: MoveOrigin // // Synopsis: The co-ordinate origin is WRT to the lower of the two: // a. Watch Segment // b. The "anchor" segment. // // When the "fetch" segment is before this origin, then some of // the co-ordinates like the _iWatchNew and _iFetch will be < 0. // In-order to have all our co-ordinates always postive, we will // the origin to the "fetch" segment. // // Arguments: [cDelta] - The number of rows to move the origin by. // This MUST be -ve. // // History: 9-05-95 srikants Created // // Notes: // //---------------------------------------------------------------------------- void CRegionTransformer::MoveOrigin( DBROWCOUNT cDelta ) { Win4Assert( cDelta < 0 ); Win4Assert( _iFetch < 0 ); Win4Assert( _iWatchNew < 0 ); cDelta = -cDelta; Win4Assert( cDelta >= -_iFetch ); _iWatchNew += cDelta; _iWatch += cDelta; _iFetch += cDelta; Win4Assert( _iWatchNew >= 0 && _iWatch >= 0 && _iFetch >= 0 ); } //+--------------------------------------------------------------------------- // // Member: CRegionTransformer::DecrementFetchCount // // Synopsis: // // Arguments: [rowLocator] - // [iter] - // [list] - // // Returns: // // Modifies: // // History: 7-26-95 srikants Created // // Notes: // //---------------------------------------------------------------------------- void CRegionTransformer::DecrementFetchCount( CTableRowLocator & rowLocator, CFwdTableSegIter & iter, CTableSegList & list ) { Win4Assert( list.AtEnd(iter) ); DBROWCOUNT cDiff = rowLocator.GetBeyondTableCount(); tbDebugOut(( DEB_REGTRANS, "CRegionTransformer::DecrementFetchCount - cDiff %d\n", cDiff )); if ( (_cFetch <= 0 && cDiff <= 0) || (_cFetch >= 0 && cDiff >= 0) ) { tbDebugOut(( DEB_REGTRANS, "Beyond End of Table\n" )); _cFetch = 0; } else if ( _cFetch < 0 ) { // // We are doing a reverse retrieval of rows. We must decrease the // number of rows to be retrieved by the amount we overshot. // Win4Assert( cDiff > 0 ); _cFetch += cDiff; if ( _cFetch >= 0 ) { _cFetch = 0; _cWatchNew = 0; } else { Win4Assert( _cWatchNew >= _cFetch ); Win4Assert( !"The logic here is not clear. Check it properly" ); rowLocator.SeekAndSetFetchBmk( WORKID_TBLLAST, iter ); DBROWCOUNT iOffset = (DBROWCOUNT) iter.GetSegment()->RowCount(); if ( iOffset > 0 ) { iOffset--; } _iFetch = iOffset; } } else { Win4Assert( cDiff < 0 ); Win4Assert( !IsWatched() || _iWatchNew <= 0 ); _cFetch += cDiff; _iWatchNew = 0; if ( _cFetch <= 0 ) { _cFetch = 0; _cWatchNew = 0; } else { Win4Assert( !IsWatched() || _cWatchNew >= _cFetch ); rowLocator.SeekAndSetFetchBmk( WORKID_TBLFIRST, iter ); } } return; }