windows-nt/Source/XPSP1/NT/inetsrv/query/bigtable/regtrans.cxx
2020-09-26 16:20:57 +08:00

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;
}