|
|
//+-------------------------------------------------------------------------
//
// Copyright (C) 1994-1997, Microsoft Corporation.
//
// File: rowseek.cxx
//
// Contents: Classes which encapsulate a positioning operation
// for a table.
//
// Classes: CRowSeekDescription
// CRowSeekNext
// CRowSeekAt
// CRowSeekAtRatio
// CRowSeekByBookmark
//
// History: 06 Apr 1995 AlanW Created
//
//--------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <query.hxx>
#include <sizeser.hxx>
#include "tabledbg.hxx"
#include "rowseek.hxx"
//+---------------------------------------------------------------------------
//
// Member: CRowSeekDescription::MarshalledSize, public
//
// Synopsis: Return Serialized size of a CRowSeekDescription structure
//
// Arguments: - none -
//
// Returns: unsigned - size in bytes of serialized structure.
//
// Notes: The returned size should be the maximum of the serialized
// size on input and output. None of the seek descriptions
// grow on output, so the input size may be larger than the
// output size.
//
// History: 02 May 1995 AlanW Created
//
//----------------------------------------------------------------------------
unsigned CRowSeekDescription::MarshalledSize( ) const { //
// Determine the size of the serialized seek description
//
CSizeSerStream stmSize; Marshall(stmSize);
return stmSize.Size(); }
//+---------------------------------------------------------------------------
//
// Member: CRowSeekDescription::MarshallBase, public
//
// Synopsis: Serialize the base CRowSeekDescription structure
//
// Arguments: [stm] -- stream structure is serialized into
// [eType] -- type descriminator for derived class
//
// Returns: nothing
//
// History: 29 Jan 1995 AlanW Created
//
//----------------------------------------------------------------------------
void CRowSeekDescription::MarshallBase( PSerStream & stm, DWORD eType ) const { stm.PutULong(eType); stm.PutULong(GetChapter()); }
//+---------------------------------------------------------------------------
//
// Member: CRowSeekNext::Marshall, public
//
// Synopsis: Serialize a CRowSeekNext structure
//
// Arguments: [stm] -- stream structure is serialized into
//
// Returns: nothing
//
// History: 29 Jan 1995 AlanW Created
//
//----------------------------------------------------------------------------
void CRowSeekNext::Marshall( PSerStream & stm ) const { CRowSeekDescription::MarshallBase( stm, eRowSeekCurrent ); stm.PutULong(GetSkip()); }
//+---------------------------------------------------------------------------
//
// Member: CRowSeekAt::Marshall, public
//
// Synopsis: Serialize a CRowSeekAt structure
//
// Arguments: [stm] -- stream structure is serialized into
//
// Returns: nothing
//
// History: 29 Jan 1995 AlanW Created
//
//----------------------------------------------------------------------------
void CRowSeekAt::Marshall( PSerStream & stm ) const { CRowSeekDescription::MarshallBase( stm, eRowSeekAt );
stm.PutULong(Bmk()); stm.PutLong(Offset()); stm.PutULong(ULONG(_hRegion)); }
//+---------------------------------------------------------------------------
//
// Member: CRowSeekAtRatio::Marshall, public
//
// Synopsis: Serialize a CRowSeekAtRatio structure
//
// Arguments: [stm] -- stream structure is serialized into
//
// Returns: nothing
//
// History: 29 Jan 1995 AlanW Created
//
//----------------------------------------------------------------------------
void CRowSeekAtRatio::Marshall( PSerStream & stm) const { CRowSeekDescription::MarshallBase( stm, eRowSeekAtRatio ); stm.PutULong(RatioNumerator()); stm.PutULong(RatioDenominator()); stm.PutULong(ULONG(_hRegion)); }
//+---------------------------------------------------------------------------
//
// Member: CRowSeekByBookmark::Marshall, public
//
// Synopsis: Serialize a CRowSeekByBookmark structure
//
// Arguments: [stm] -- stream structure is serialized into
//
// Returns: nothing
//
// Notes: When serializing ByBookmarks, we only do bookmarks
// or statuses, not both. Only one must exist in the structure.
//
// History: 29 Jan 1995 AlanW Created
//
//----------------------------------------------------------------------------
void CRowSeekByBookmark::Marshall(PSerStream & stm) const { Win4Assert(_cBookmarks == 0 || _cValidRet == 0);
CRowSeekDescription::MarshallBase( stm, eRowSeekByBookmark );
stm.PutULong(_cBookmarks); for (unsigned i = 0; i < _cBookmarks; i++) stm.PutULong(_aBookmarks[i]);
stm.PutULong(_cValidRet); for (i = 0; i < _cValidRet; i++) stm.PutULong(_ascRet[i]); }
//+---------------------------------------------------------------------------
//
// Member: CRowSeekNext::CRowSeekNext, public
//
// Synopsis: DeSerialize a CRowSeekNext structure
//
// Arguments: [stm] -- input stream structure is read from
// [iVersion] -- input stream version
//
// Returns: nothing
//
// History: 06 Apr 1995 AlanW Created
//
//----------------------------------------------------------------------------
CRowSeekNext::CRowSeekNext( PDeSerStream & stm, int iVersion ) : CRowSeekDescription( eRowSeekCurrent, 0 ) { SetChapter( stm.GetULong() ); SetSkip( stm.GetULong() ); }
//+---------------------------------------------------------------------------
//
// Member: CRowSeekAt::CRowSeekAt, public
//
// Synopsis: DeSerialize a CRowSeekAt structure
//
// Arguments: [stm] -- input stream structure is read from
//
// Returns: nothing
//
// History: 06 Apr 1995 AlanW Created
//
//----------------------------------------------------------------------------
CRowSeekAt::CRowSeekAt( PDeSerStream & stm, int iVersion ) : CRowSeekDescription( eRowSeekAt, 0 ) { SetChapter( stm.GetULong() ); _bmkOffset = stm.GetULong(); _cRowsOffset = stm.GetLong(); _hRegion = (HWATCHREGION) stm.GetULong(); }
//+---------------------------------------------------------------------------
//
// Member: CRowSeekAtRatio::CRowSeekAtRatio, public
//
// Synopsis: DeSerialize a CRowSeekAtRatio structure
//
// Arguments: [stm] -- input stream structure is read from
//
// Returns: nothing
//
// History: 06 Apr 1995 AlanW Created
//
//----------------------------------------------------------------------------
CRowSeekAtRatio::CRowSeekAtRatio( PDeSerStream & stm, int iVersion ) : CRowSeekDescription( eRowSeekAtRatio, 0 ) { SetChapter( stm.GetULong() ); _ulNumerator = stm.GetULong(); _ulDenominator = stm.GetULong(); _hRegion = (HWATCHREGION) stm.GetULong(); }
//+---------------------------------------------------------------------------
//
// Member: CRowSeekByBookmark::CRowSeekByBookmark, public
//
// Synopsis: DeSerialize a CRowSeekByBookmark structure
//
// Arguments: [stm] -- input stream structure is read from
//
// Returns: nothing
//
// History: 06 Apr 1995 AlanW Created
//
//----------------------------------------------------------------------------
CRowSeekByBookmark::CRowSeekByBookmark( PDeSerStream & stm, int iVersion ) : CRowSeekDescription( eRowSeekByBookmark, 0 ), _aBookmarks( 0 ), _ascRet( 0 ) { SetChapter( stm.GetULong() );
_cBookmarks = stm.GetULong(); if (_cBookmarks) { // Protect agains unreasonable requests, which probably are attacks
if ( _cBookmarks >= 65536 ) THROW( CException( E_INVALIDARG ) );
_aBookmarks = new CI_TBL_BMK [ _cBookmarks ];
for (unsigned i = 0; i < _cBookmarks; i++) _aBookmarks[i] = stm.GetULong(); }
_maxRet = _cValidRet = stm.GetULong();
if (_cValidRet) { // Protect against unreasonable requests, which probably are attacks
if ( _cValidRet >= 65536 ) THROW( CException( E_INVALIDARG ) );
_ascRet = new SCODE [ _cValidRet ];
for (unsigned i = 0; i < _cValidRet; i++) _ascRet[i] = stm.GetULong(); }
//
// We don't expect both bookmarks and statuses.
//
Win4Assert(_cBookmarks == 0 || _cValidRet == 0); }
//+---------------------------------------------------------------------------
//
// Member: CRowSeekByBookmark::~CRowSeekByBookmark, public
//
// Synopsis: Destroy a CRowSeekByBookmark structure
//
// Returns: nothing
//
// History: 29 Jan 1995 AlanW Created
//
//----------------------------------------------------------------------------
CRowSeekByBookmark::~CRowSeekByBookmark( ) { delete _aBookmarks; delete _ascRet; }
//+-------------------------------------------------------------------------
//
// Member: CRowSeekNext::GetRows, public
//
// Synopsis: Retrieve row data for a table cursor
//
// Arguments: [rCursor] - the cursor to fetch data for
// [rTable] - the table from which data is fetched
// [rFetchParams] - row fetch parameters and buffer pointers
// [pSeekDescOut] - pointer to seek description for restart
//
// Returns: SCODE - the status of the operation.
//
// Notes:
//
// History: 07 Apr 1995 Alanw Created
//
//--------------------------------------------------------------------------
SCODE CRowSeekNext::GetRows( CTableCursor& rCursor, CTableSource& rTable, CGetRowsParams& rFetchParams, XPtr<CRowSeekDescription>& pSeekDescOut) const { LONG cRowsToSkip = GetSkip();
if (cRowsToSkip) { tbDebugOut(( DEB_IWARN, "CRowSeekNext::GetRows - non-zero skip count %d\n", cRowsToSkip )); }
WORKID widStart; if ( rTable.IsFirstGetNextRows() ) { //
// For the first GetNextRows call, the start position is
// beginning of table if cRowsToSkip is positive, and end
// of table if its negative. For subsequent calls, the
// current position is the start position.
//
if ( cRowsToSkip >= 0 ) widStart = WORKID_TBLBEFOREFIRST; else widStart = WORKID_TBLAFTERLAST; } else widStart = rTable.GetCurrentPosition( GetChapter() );
WORKID widEnd = widStart;
//
// OffsetSameDirFetch implements the skip of one row that
// Oledb::GetNextRows requires on the first fetch
// when scrolling and fetching are in the same direction,
// and for subsequent fetches when the fetch is in the
// same direction as previous fetch. When the direction is
// reversed the first wid fetched is same as the last wid
// returned from the previous call, and offsetSameDirFetch
// is 0 in this case.
//
LONG offsetSameDirFetch = 0; if ( rTable.IsFirstGetNextRows() ) { if ( cRowsToSkip >= 0 && rFetchParams.GetFwdFetch() ) offsetSameDirFetch = 1; else if ( cRowsToSkip < 0 && !rFetchParams.GetFwdFetch() ) offsetSameDirFetch = -1; } else { if ( rFetchParams.GetFwdFetch() == rTable.GetFwdFetchPrev() ) { if ( rFetchParams.GetFwdFetch() ) offsetSameDirFetch = 1; else offsetSameDirFetch = -1; } }
SCODE scRet = rTable.GetRowsAt( 0, // no watch region
widStart, GetChapter(), cRowsToSkip + offsetSameDirFetch, rCursor.GetBindings(), rFetchParams, widEnd );
//
// Don't attempt to save the widEnd if the positioning
// operation got us past the end of the table. Storing
// widEnd in rCursor will cause us to be stuck at the
// end, with no way to get any more rows. In this situation,
// we don't expect to have successfully transferred any rows.
//
// NOTE: don't throw, the error may need to be seen by caller
// in CRowset::_FetchRows
//
if ( WORKID_TBLAFTERLAST == widEnd || WORKID_TBLBEFOREFIRST == widEnd || ( scRet == DB_E_BADSTARTPOSITION && cRowsToSkip == 0 ) ) { Win4Assert(rFetchParams.RowsTransferred() == 0); return DB_S_ENDOFROWSET; }
if (SUCCEEDED(scRet)) { rTable.SetCurrentPosition( GetChapter(), widEnd ); rTable.SetFwdFetchPrev( rFetchParams.GetFwdFetch() ); rTable.ResetFirstGetNextRows(); } else { tbDebugOut(( DEB_WARN, "CRowSeekNext::GetRows failed, sc=%x\n", scRet )); }
if (DB_S_BLOCKLIMITEDROWS == scRet) { Win4Assert(rFetchParams.RowsTransferred() > 0); pSeekDescOut.Set(new CRowSeekNext(GetChapter(), 0) ); }
return scRet; }
//+-------------------------------------------------------------------------
//
// Member: CRowSeekAt::GetRows, public
//
// Synopsis: Retrieve row data for a table cursor
//
// Arguments: [rCursor] - the cursor to fetch data for
// [rTable] - the table from which data is fetched
// [rFetchParams] - row fetch parameters and buffer pointers
// [pSeekDescOut] - pointer to seek description for restart
//
// Returns: SCODE - the status of the operation.
//
// Notes:
//
// History: 07 Apr 1995 Alanw Created
//
//--------------------------------------------------------------------------
SCODE CRowSeekAt::GetRows( CTableCursor& rCursor, CTableSource& rTable, CGetRowsParams& rFetchParams, XPtr<CRowSeekDescription>& pSeekDescOut) const { WORKID widStart = Bmk(); LONG iRowOffset = Offset();
SCODE scRet = rTable.GetRowsAt( _hRegion, widStart, GetChapter(), iRowOffset, rCursor.GetBindings(), rFetchParams, widStart );
// The first fetch took care of the hRegion manipulation
// set the new seek descriptor's hRegion to 0
if (DB_S_BLOCKLIMITEDROWS == scRet) { Win4Assert(rFetchParams.RowsTransferred() > 0); pSeekDescOut.Set(new CRowSeekAt(0, GetChapter(), rFetchParams.GetFwdFetch() ? 1 : -1, widStart) ); }
return scRet; }
//+-------------------------------------------------------------------------
//
// Member: CRowSeekAtRatio::GetRows, public
//
// Synopsis: Retrieve row data for a table cursor
//
// Arguments: [rCursor] - the cursor to fetch data for
// [rTable] - the table from which data is fetched
// [rFetchParams] - row fetch parameters and buffer pointers
// [pSeekDescOut] - pointer to seek description for restart
//
// Returns: SCODE - the status of the operation.
//
// Notes:
//
// History: 07 Apr 1995 Alanw Created
//
//--------------------------------------------------------------------------
SCODE CRowSeekAtRatio::GetRows( CTableCursor& rCursor, CTableSource& rTable, CGetRowsParams& rFetchParams, XPtr<CRowSeekDescription>& pSeekDescOut) const { WORKID widRestart = widInvalid; SCODE scRet = rTable.GetRowsAtRatio( _hRegion, RatioNumerator(), RatioDenominator(), GetChapter(), rCursor.GetBindings(), rFetchParams, widRestart );
// The first fetch took care of the hRegion manipulation
// set the new seek descriptor's hRegion to 0
if (DB_S_BLOCKLIMITEDROWS == scRet) { Win4Assert(rFetchParams.RowsTransferred() > 0); pSeekDescOut.Set(new CRowSeekAt(0, GetChapter(), 1, widRestart) ); }
return scRet; }
//+-------------------------------------------------------------------------
//
// Member: CRowSeekByBookmark::GetRows, public
//
// Synopsis: Retrieve row data for a table cursor
//
// Arguments: [rCursor] - the cursor to fetch data for
// [rTable] - the table from which data is fetched
// [rFetchParams] - row fetch parameters and buffer pointers
// [pSeekDescOut] - pointer to seek description for restart
//
// Returns: SCODE - the status of the operation.
//
//
// History: 07 Apr 1995 Alanw Created
//
//--------------------------------------------------------------------------
SCODE CRowSeekByBookmark::GetRows( CTableCursor& rCursor, CTableSource& rTable, CGetRowsParams& rFetchParams, XPtr<CRowSeekDescription>& pSeekDescOut) const { unsigned cFailed = 0; ULONG cSavedRowsReq = rFetchParams.RowsToTransfer();
Win4Assert(_cBookmarks > 0); Win4Assert(cSavedRowsReq <= _cBookmarks); Win4Assert(0 == rFetchParams.RowsTransferred() && cSavedRowsReq > 0);
rFetchParams.SetRowsRequested(0);
SCODE scRet = S_OK;
TRY { XPtr<CRowSeekByBookmark> pSeekOut( new CRowSeekByBookmark(GetChapter(), _cBookmarks) );
BOOL fFailed = FALSE; // Iterate over bookmarks, calling rTable.GetRowsAt for each
for (unsigned i = 0; i < cSavedRowsReq; i++) { if (! fFailed) rFetchParams.IncrementRowsRequested( );
WORKID widNext = _aBookmarks[i]; if (widNext == widInvalid) { scRet = DB_E_BADBOOKMARK; } else { TRY { scRet = rTable.GetRowsAt( 0, // no watch region
widNext, GetChapter(), 0, rCursor.GetBindings(), rFetchParams, widNext ); } CATCH( CException, e ) { scRet = e.GetErrorCode(); Win4Assert( scRet != STATUS_ACCESS_VIOLATION && scRet != STATUS_NO_MEMORY ); } END_CATCH;
if (! SUCCEEDED(scRet) && scRet != STATUS_BUFFER_TOO_SMALL ) scRet = DB_E_BOOKMARKSKIPPED; }
if (scRet == DB_S_ENDOFROWSET) scRet = S_OK;
if ( STATUS_BUFFER_TOO_SMALL == scRet || DB_S_BLOCKLIMITEDROWS == scRet ) { scRet = DB_S_BLOCKLIMITEDROWS; break; }
//
// set per-row error status
//
pSeekOut->_SetStatus(i, scRet); if (FAILED(scRet)) { cFailed++; fFailed = TRUE; } else fFailed = FALSE; } pSeekDescOut.Set( pSeekOut.Acquire() ); } CATCH( CException, e ) { scRet = e.GetErrorCode(); } END_CATCH;
if (cFailed) return DB_S_ERRORSOCCURRED; else if (0 == rFetchParams.RowsTransferred()) return STATUS_BUFFER_TOO_SMALL; else return S_OK; }
//+-------------------------------------------------------------------------
//
// Member: CRowSeekByBookmark::_SetStatus, private
//
// Synopsis: Set row status for a bookmark lookup
//
// Arguments: [iBmk] - index of bookmark to set status for
// [scRet] - the status to be saved
//
// Returns: Nothing
//
// History: 12 Apr 1995 Alanw Created
//
//--------------------------------------------------------------------------
void CRowSeekByBookmark::_SetStatus( unsigned iBmk, SCODE scRet ) { Win4Assert( iBmk < _maxRet );
if (_ascRet == 0) _ascRet = new SCODE[_maxRet];
_ascRet[iBmk] = scRet; if (iBmk >= _cValidRet) { Win4Assert( iBmk == _cValidRet ); _cValidRet = iBmk + 1; } }
//+-------------------------------------------------------------------------
//
// Member: CRowSeekDescription::MergeResults, public
//
// Synopsis: Update seek description state after a transfer
//
// Arguments: [pRowSeek] - row seek description after transfer
//
// Returns: Nothing
//
// Notes: Used only in user mode. Does nothing for CRowSeekNext,
// CRowSeekAt and CRowSeekAtRatio.
//
// History: 02 May 1995 Alanw Created
//
//--------------------------------------------------------------------------
void CRowSeekDescription::MergeResults( CRowSeekDescription * pRowSeek ) { return; }
//+-------------------------------------------------------------------------
//
// Member: CRowSeekByBookmark::MergeResults, public
//
// Synopsis: Update seek description state after a transfer
//
// Arguments: [pRowSeek] - row seek description after transfer
//
// Returns: Nothing
//
// Notes: Used only in user mode. Transfers statuses into
// original rowseek and bookmarks from original to
// result rowseek.
//
// History: 02 May 1995 Alanw Created
//
//--------------------------------------------------------------------------
void CRowSeekByBookmark::MergeResults( CRowSeekDescription * pRowSeekDesc) { Win4Assert(pRowSeekDesc->IsByBmkRowSeek());
CRowSeekByBookmark* pRowSeek = (CRowSeekByBookmark*) pRowSeekDesc;
Win4Assert(_cBookmarks > 0 && pRowSeek->_cValidRet > 0 && pRowSeek->_cBookmarks == 0);
//
// Transfer return statuses to this object from the other
//
unsigned iBaseRet = _cValidRet;
for (unsigned i=0; i < pRowSeek->_cValidRet; i++) { _SetStatus( i+iBaseRet, pRowSeek->_ascRet[i] ); }
delete [] pRowSeek->_ascRet; pRowSeek->_ascRet = 0; pRowSeek->_cValidRet = pRowSeek->_maxRet = 0;
//
// Transfer bookmarks from this object to the other.
//
if (_cBookmarks - _cValidRet > 0) { pRowSeek->_cBookmarks = _cBookmarks - _cValidRet; pRowSeek->_aBookmarks = new CI_TBL_BMK[ pRowSeek->_cBookmarks ];
for (unsigned i=0; i<pRowSeek->_cBookmarks; i++) { pRowSeek->_aBookmarks[i] = _aBookmarks[ i+_cValidRet ]; } } }
|