543 lines
15 KiB
C++
543 lines
15 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1994 - 2000.
|
||
|
//
|
||
|
// File: regtrans.cxx
|
||
|
//
|
||
|
// Contents: Watch Region Transformer
|
||
|
//
|
||
|
// Classes: CRegionTransformer
|
||
|
//
|
||
|
// History: 20-Jul-95 BartoszM Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
#include <pch.cxx>
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <seglist.hxx>
|
||
|
#include <wregion.hxx>
|
||
|
|
||
|
#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;
|
||
|
|
||
|
}
|