|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1994 - 2000.
//
// File: tblwindo.hxx
//
// Contents: Declaration of the CTableWindow class, a component of
// a large table.
//
// Classes: CTableWindow
//
// History: 14 Jun 1994 Alanw Created
// 20 Jun 1995 BartoszM Added watch regions
//
//--------------------------------------------------------------------------
#pragma once
#include <tableseg.hxx>
#include <shardbuf.hxx> // Shared buffer
#include "tblvarnt.hxx" // for CTableVariant
#include "rowcomp.hxx" // for CRowCompareXX
#include "rowindex.hxx" // for CRowIndex
#include "bmkmap.hxx" // for Book Mark Mapping
#include "wnotifmg.hxx" // Watch region notifications manager
class CTableWindowSplit; class CTableRowKey; class CPathStore; class CSingletonCursor;
class CWindowWatch { public:
HWATCHREGION _hRegion; long _iRowStart; long _cRowsHere; // rows watched in this window
long _cRowsLeft; // rows watched here and in following segments
};
class CChangeScript; // NEWFEATURE - until we give change scripts.
//+-------------------------------------------------------------------------
//
// Class: CTableWindow
//
// Purpose: A segment of a large table which is fully buffered in
// memory.
// It can be directly transferred to the user from the
// cached rowdata.
//
// Interface:
//
//--------------------------------------------------------------------------
class CTableWindow : public CTableSegment { INLINE_UNWIND( CTableWindow )
friend CRowCompareVariant; friend class CTableWindowSplit; friend class CLargeTable; friend class CWindowRowIter; friend class CTableRowLocator; friend class CBucketizeWindows;
public: //
// Indicator values for data values.
//
// NOTE: These values need to be translated between these values
// and the standard defines used by OLE DB. We define our
// own values so we can store them in a byte (or smaller)
// field in the row data.
//
enum TableIndicator { TBL_DATA_OKAY = 0, // data stored okay
TBL_DATA_OUTOFRANGE, // range error, e.g., long into short
TBL_DATA_CANTCOERCE, // type mismatch
TBL_DATA_USEENTRYID, // entry too big, use entry ID
TBL_DATA_OVERRUN, // value too big for data area
TBL_DATA_EMPTY, // no value for this data point
TBL_DATA_ROWADDED, // row status: added after cursor created
TBL_DATA_BADBOOKMARK, // row status: bookmark for row was invalid
TBL_DATA_PENDING_DELETE, // row status: pending delete
TBL_DATA_HARD_DELETE // row status: hard deleted; not visible
};
CTableWindow( CSortSet const * pSortSet, CTableKeyCompare & comparator, CColumnMasterSet * pMasterColumns, ULONG segId, CCategorize *pCategorizer, CSharedBuffer & sharedBuf, CQAsyncExecute & QExecute );
CTableWindow( CTableWindow & src, ULONG segId );
~CTableWindow();
// Virtual methods inherited from CTableSink
WORKID PathToWorkID( CRetriever& obj, CTableSink::ERowType eRowType );
BOOL PutRow( CRetriever & obj, CTableSink::ERowType eRowType ) { Win4Assert( !"Must not be called" ); return FALSE; }
BOOL RemoveRow( PROPVARIANT const & varUnique, WORKID & widNext, CI_TBL_CHAPT & chapt );
CSortSet const & SortOrder();
// Virtual methods inherited from CTableSegment
BOOL PutRow( CRetriever & obj, CTableRowKey & currKey );
DBCOUNTITEM RowCount() { return _visibleRowIndex.RowCount(); }
SCODE GetRows( HWATCHREGION hRegion, WORKID widStart, CI_TBL_CHAPT chapt, ULONG & cRowsToGet, CTableColumnSet const & rOutColumns, CGetRowsParams& rGetParams, WORKID& rwidNextRowToTransfer );
void LokGetOneColumn( WORKID wid, CTableColumn const & rOutColumn, BYTE * pbOut, PVarAllocator & rVarAllocator );
BOOL IsRowInSegment( WORKID wid );
BOOL IsPendingDelete( WORKID wid );
void CompareRange( CRetriever &obj, CCompareResult & rslt );
SCODE GetNotifications( CNotificationParams &rParams );
// Other public methods
BOOL RowOffset(WORKID wid, ULONG & iRow) { if ( widInvalid == wid ) return FALSE;
TBL_OFF obRowOffset = 0; if ( FindBookMark( wid, obRowOffset, iRow ) ) return TRUE; else return _FindWorkId(wid, obRowOffset, iRow); }
BOOL FindBookMark( WORKID wid, TBL_OFF &obRow, ULONG & iRow );
WORKID GetBookMarkAt( ULONG iRow );
WORKID GetFirstBookMark();
int CompressData(); // attempt to reduce data storage needs
inline ULONG MemUsed( void ) { // PERFFIX - also need so sum all non-global, non-shared compressions
return _cbHeapUsed + _DataAllocator.MemUsed(); }
BOOL IsSortedSplit( ULONG & riSplit ) { return _GetInvisibleRowIndex().FindMidSplitPoint( riSplit ); }
BOOL IsEmptyForQuery();
BOOL IsGettingFull();
unsigned PercentFull();
// Watch region manipulations
long AddWatch (HWATCHREGION hRegion, LONG iStart, LONG cRows, BOOL isLast);
long ModifyWatch (HWATCHREGION hRegion, LONG iStart, LONG cRows, BOOL isLast);
long DeleteWatch (HWATCHREGION hRegion);
long ShrinkWatch (HWATCHREGION hRegion, CI_TBL_BMK bookmark, LONG cRows);
long ShrinkWatch (HWATCHREGION hRegion, LONG cRows);
BOOL HasWatch (HWATCHREGION hRegion);
BOOL IsWatched (HWATCHREGION hRegion, CI_TBL_BMK bookmark);
BOOL IsWatched() { if ( _aWindowWatch.Count() > 0 ) { if ( _xDeltaBookMarkMap.IsNull() ) _xDeltaBookMarkMap.Set( new CBookMarkMap( _dynRowIndex ) ); return TRUE; }
return FALSE; }
long RowsWatched (HWATCHREGION hRegion);
WORKID RowWorkid(BYTE *pRow) { return *(WORKID *) (pRow + _iOffsetWid); }
LONG RowRank(BYTE *pRow) { return ( ULONG_MAX == _iOffsetRank ) ? MAX_QUERY_RANK : *(LONG *) (pRow + _iOffsetRank); }
LONG RowHitCount(BYTE *pRow) { return ( ULONG_MAX == _iOffsetHitCount ) ? 0 : *(LONG *) (pRow + _iOffsetHitCount); }
long GetWatchStart( HWATCHREGION hRegion) const { unsigned i = FindRegion(hRegion); Win4Assert (i < _aWindowWatch.Count());
return _aWindowWatch.Get(i)._iRowStart; }
BOOL FindNearestDynamicBmk( CI_TBL_CHAPT chapter, CI_TBL_BMK & bookmark );
BOOL FindFirstNonDeleteDynamicBmk( CI_TBL_BMK & bookmark );
BOOL FindLastNonDeleteDynamicBmk( CI_TBL_BMK & bookmark );
BOOL IsFirstRowFirstOfCategory();
#ifdef CIEXTMODE
void CiExtDump(void *ciExtSelf); #endif
private:
//
// No Copy consructor allowed for this.
//
CTableWindow( CTableWindow & src );
void _FinishInit( CTableRowAlloc & rowMap, unsigned &maxAlignment );
CSharedBuffer & _GetSharedBuf() const { return _sharedBuf; }
void _InitSortComparators();
void _PopulateRow( CRetriever &obj, BYTE *pThisRow, WORKID wid );
BOOL _FindWorkId( WORKID wid, TBL_OFF & obRow, ULONG & iRow );
WORKID _GetWorkIdAt( ULONG iRow );
WORKID _GetFirstWorkId();
WORKID _GetLastWorkId();
void _AddColumnDesc( CColumnMasterDesc& MasterCol, CTableRowAlloc& RowMap, unsigned& maxAlignment);
void _AddColumnDesc( CTableColumn & src, CTableRowAlloc& RowMap, unsigned& maxAlignment);
void _AddWatchItem (CWindowWatch& watch);
void _RemoveWatchItem (unsigned i);
CRowIndex & _GetInvisibleRowIndex() { return IsWatched() ? _dynRowIndex : _visibleRowIndex; }
//
// Methods used for window->bucket conversion
//
void GetSortKey( ULONG iRow, CTableRowKey & bktRow );
unsigned FindRegion (HWATCHREGION hRegion) const;
void _StartStaticDynamicSplit(); void _EndStaticDynamicSplit(); void _ReconcileRowIndexes( CRowIndex & dst , CRowIndex & src ); void _CleanupAndReconcileRowIndexes( BOOL fCreatingWatch ); void _Refresh();
//
// Storage for fixed length row data
//
unsigned _cbRowSize; // size in bytes of data for each row
unsigned _iOffsetWid; // offset of WorkID in row data
unsigned _iOffsetRank; // offset of rank in row data
unsigned _iOffsetHitCount; // offset of hitcount in row data
unsigned _iOffsetRowStatus; // offset of row status in row data
unsigned _iOffsetChapter; // offset of chapter number (optional)
CTableColumnSet _Columns; // column descriptions for this window
//
// Shared buffer for the whole table used as temporary memory.
//
CSharedBuffer & _sharedBuf;
XPtr<CSingletonCursor> _xCursor; // singleton cursor used in GetRows
//
// Memory management related methods and variables.
//
BYTE * _RowAlloc( void ) { _cRowsAllocated++; // Just get a new row from the allocator
BYTE *pbRetBuf = (BYTE *) _DataAllocator.AllocFixed(); Win4Assert(0 != pbRetBuf); return pbRetBuf; }
//
// Additional storage for variable length data which is not
// stored as a compressed column. When first needed after a
// window is created, this will begin at the end of the block of
// data for row data, and grow downward toward it. When these
// grow enough to meet, the row data will be moved out into
// a separate block, allowing the variable data to expand into the
// newly freed area.
//
// At the time this data is moved or grown, it may be a good time to
// convert columns for compressions. All extra data for
// compressed columns will be stored with the column descriptor.
//
CFixedVarTableWindowAllocator _DataAllocator; // Variable data allocator
ULONG _cbHeapUsed; // total heap memory used by structure
CPathStore * _pPathStore; // Store for paths.
//
// Row indirection object. This holds offsets in the heap where each
// row resides. The row index is sorted by the current sort order.
//
CRowIndex _dynRowIndex;
//
// The "static" row index that will be used for giving rows to the
// client (user).
//
CRowIndex _visibleRowIndex;
//
// BookMark mapping object. If there are no notifications, it is
// associated with the _dynRowIndex; o/w it is associated with the
// _visibleRowIndex.
//
CBookMarkMap _BookMarkMap;
//
// BookMark mapping object for the "deltas" or changes pending
// notification to the user. It is always associated with the _dynRowIndex
//
XPtr<CBookMarkMap> _xDeltaBookMarkMap;
//
// Notification processing object
//
CDynArrayInPlace<CWindowWatch> _aWindowWatch;
//
// Row sorting objects.
//
XPtr<CRowCompareVariant> _RowCompare; XPtr<CRowCompare> _QuickRowCompare; CSortSet const * _pSortSet;
ULONG _cPendingDeletes; // # of rows with pending deletes. These are
// visible to retrievals.
ULONG _cRowsHardDeleted; // # of rows "hard" deleted - not visible to
// retrievals.
ULONG _cRowsAllocated; // # of rows allocated in the table
BOOL _fSplitInProgress; // Flag set to TRUE when a window split is
// in progress.
CQAsyncExecute & _QueryExecute; // The query object that will be used
// when retrieving the partial deferred cols.
BOOL _IsTableWatched() const;
ULONG _AllocatedRowCount() { return _cRowsAllocated; }
BOOL _fCanPartialDefer ; // Is set in constructor by taking value from the query session
//
// Functions to get at row metadata that always exists
//
void _SetRowWorkid(BYTE *pRow,WORKID wid) { *(WORKID *) (pRow + _iOffsetWid) = wid; } ULONG _RowStatus(BYTE *pRow) { return *(BYTE *) (pRow + _iOffsetRowStatus); } void _SetRowStatus(BYTE *pRow,BYTE status) { *(BYTE *) (pRow + _iOffsetRowStatus) = status; }
ULONG _RowChapter(BYTE *pRow) { return *(unsigned *) (pRow + _iOffsetChapter); }
void _SetChapter(BYTE *pRow,unsigned Chapter) { *(unsigned *) (pRow + _iOffsetChapter) = Chapter; }
//
// Methods to support window splitting. These will be used by the
// CTableWindowSplit class.
//
CRowIndex & _GetVisibleRowIndex() { return _visibleRowIndex; }
CRowIndex & _GetDynamicRowIndex() { return _dynRowIndex; }
BYTE * _GetRow( TBL_OFF oTableRow ) { return (BYTE *) _DataAllocator.FixedPointer( oTableRow ); }
void _PutRowToVisibleRowIndex( CTableWindow & srcWindow, TBL_OFF oSrcRow );
void _PutRowToDynRowIndex( CTableWindow & srcWindow, TBL_OFF oSrcRow );
TBL_OFF _CopyRow( CTableWindow & srcWindow, TBL_OFF oSrcRow );
WORKID _GetWorkId( TBL_OFF oTableRow ) { BYTE * pbRow = _GetRow( oTableRow ); return RowWorkid( pbRow ); }
LONG _GetRank( TBL_OFF oTableRow ) { BYTE * pbRow = _GetRow( oTableRow ); return RowRank( pbRow ); }
LONG _GetHitCount( TBL_OFF oTableRow ) { BYTE * pbRow = _GetRow( oTableRow ); return RowHitCount( pbRow ); }
BOOL _IsRowDeleted( TBL_OFF oTableRow ) { BYTE * pbRow = _GetRow( oTableRow ); const ULONG rowStatus = _RowStatus( pbRow ); return TBL_DATA_PENDING_DELETE == rowStatus || TBL_DATA_HARD_DELETE == rowStatus ; }
BOOL _IsWorkIdInVisRowIndex( WORKID wid ) { return _BookMarkMap.IsBookMarkPresent(wid); }
BOOL _IsRowInVisRowIndex( TBL_OFF oTableRow ) { BYTE * pbRow = _GetRow(oTableRow); Win4Assert( pbRow ); WORKID wid = RowWorkid(pbRow); TBL_OFF oRowFound; BOOL fFound = _BookMarkMap.FindBookMark( wid, oRowFound ); return fFound && oRowFound == oTableRow; }
int _CompareRows( TBL_OFF obRow1, TBL_OFF obRow2 ) { if ( 0 != _QuickRowCompare.GetPointer() ) return _QuickRowCompare->Compare( obRow1, obRow2 ); else return _RowCompare->Compare( obRow1, obRow2 ); }
BYTE * _GetRowFromIndex( ULONG iRow, CRowIndex & rowIndex ) { return _GetRow( rowIndex.GetRow( iRow ) ); }
void _SetSplitInProgress() { _fSplitInProgress = TRUE; } void _SetSplitDone() { _fSplitInProgress = FALSE; }
void _CopyColumnData( BYTE* pbSrcRow, BYTE* pbOutRow, CTableColumn **pTableCols, CTableColumnSet const& rOutColumns, PVarAllocator& rDstPool, CRetriever* obj = NULL );
inline BOOL _CanPartialDeferCol( XPtr<CTableColumn>& xTableCol ) const { Win4Assert( xTableCol.GetPointer() ); Win4Assert( _pSortSet );
return ( xTableCol->PropId != pidWorkId && xTableCol->PropId != pidRank && xTableCol->PropId != pidRankVector && xTableCol->PropId != pidHitCount && xTableCol->PropId != pidRowStatus && xTableCol->PropId != pidChapter && xTableCol->PropId != pidSelf && !_pSortSet->Exists( xTableCol->PropId ) ); } };
//+-------------------------------------------------------------------------
//
// Member: CTableWindow::PathToWorkID, inline
//
// Synopsis: Path to WorkID conversion
//
// Arguments: [obj] -- positioned cursor to row
//
// Returns: WORKID - the WorkID assigned
//
// Notes: This method should be called only on CLargeTable.
// CLEANCODE: for now it's convenient to have this as a
// virtual method on CTableSink. It should become
// an ordinary method on CLargeTable once the
// ITable code is removed.
//
//--------------------------------------------------------------------------
inline WORKID CTableWindow::PathToWorkID( CRetriever& obj, CTableSink::ERowType eRowType ) { return 0; }
//+---------------------------------------------------------------------------
//
// Member: CTableWindow::GetBookMarkAt
//
// Synopsis: Returns a bookmark at the specified offset.
//
// Arguments: [iRow] -
//
// History: 8-04-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
inline WORKID CTableWindow::GetBookMarkAt( ULONG iRow ) { Win4Assert( iRow < _GetVisibleRowIndex().RowCount() ); return RowWorkid( _GetRowFromIndex( iRow, _GetVisibleRowIndex() ) ); }
//+---------------------------------------------------------------------------
//
// Member: CTableWindow::GetFirstBookMark
//
// Synopsis: Returns the first BOOKMARK in the window. A BOOKMARK is one
// which is visible to a client.
//
// History: 8-04-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
inline WORKID CTableWindow::GetFirstBookMark() { if ( 0 == RowCount() ) return widInvalid; else return GetBookMarkAt(0); }
//+---------------------------------------------------------------------------
//
// Member: CTableWindow::_GetWorkIdAt
//
// Synopsis: Returns the workid at the specified offset in the
// "invisible" row index , ie, query row index.
//
// Arguments: [iRow] -
//
// History: 8-02-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
inline WORKID CTableWindow::_GetWorkIdAt( ULONG iRow ) { Win4Assert( iRow < _GetInvisibleRowIndex().RowCount() ); return RowWorkid( _GetRowFromIndex(iRow , _GetInvisibleRowIndex()) ); }
//+---------------------------------------------------------------------------
//
// Function: _GetFirstWorkId
//
// Synopsis: Returns the first WORKID visible to the QUERY only. Note that
// this can be different from the first bookmark.
//
// History: 8-04-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
inline WORKID CTableWindow::_GetFirstWorkId() { if ( 0 == RowCount() ) return widInvalid; else return _GetWorkIdAt(0); }
//+---------------------------------------------------------------------------
//
// Function: _GetLastWorkId
//
// Synopsis: Returns the last WORKID visible to the QUERY only. Note that
// this can be different from the first bookmark.
//
// History: 03-12-98 vikasman Created
//
// Notes:
//
//----------------------------------------------------------------------------
inline WORKID CTableWindow::_GetLastWorkId() { if ( 0 == RowCount() ) return widInvalid; else return _GetWorkIdAt( (ULONG) RowCount() - 1); }
//+---------------------------------------------------------------------------
//
// Class: CWindowRowIter ()
//
// Purpose: An iterator to retrieve WORKIDs from the a window.
//
// History: 2-16-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
class CWindowRowIter {
public:
CWindowRowIter( CTableWindow & window ) : _window(window), _rowIndex( window._GetInvisibleRowIndex() ), _curr(0), _cTotal( _rowIndex.RowCount() ) {
}
BOOL AtEnd() const { Win4Assert( _curr <= _cTotal ); return _curr == _cTotal; }
BOOL AtEnd( ULONG iEnd ) const { Win4Assert( _curr <= _cTotal && iEnd <= _cTotal ); return _curr == iEnd; }
WORKID Get() const { Win4Assert( !AtEnd() ); TBL_OFF oTableRow = _rowIndex.GetRow(_curr); return _window._GetWorkId( oTableRow ); }
LONG Rank() const { Win4Assert( !AtEnd() ); TBL_OFF oTableRow = _rowIndex.GetRow(_curr); return _window._GetRank( oTableRow ); }
LONG HitCount() const { Win4Assert( !AtEnd() ); TBL_OFF oTableRow = _rowIndex.GetRow(_curr); return _window._GetHitCount( oTableRow ); }
BOOL IsDeletedRow() const { Win4Assert( !AtEnd() ); TBL_OFF oTableRow = _rowIndex.GetRow(_curr); return _window._IsRowDeleted( oTableRow ); }
ULONG GetCurrPos() const { return _curr; }
void Next() { Win4Assert( !AtEnd() ); _curr++; }
ULONG TotalRows() const { return _cTotal; }
private:
CTableWindow & _window; CRowIndex & _rowIndex; ULONG _curr; const ULONG _cTotal; };
|