|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1994 - 1999.
//
// File: rowbuf.cxx
//
// Contents: Declaration of the row buffer classes, used for HROW
// buffering at the interface level.
//
// Classes: CRowBuffer
// CRowBufferSet
// CDeferredValue
//
// History: 22 Nov 1994 AlanW Created
//
//--------------------------------------------------------------------------
#include "pch.cxx"
#pragma hdrstop
#include <hraccess.hxx>
#include "tabledbg.hxx"
//+-------------------------------------------------------------------------
//
// Member: CRowBufferSet constructor, public
//
// Synopsis: Create a row buffer set
//
// Arguments: [fSequential] - if TRUE, sequential rowset; obRowId
// is not required.
// [obRowRefcount] - offset in row data reserved for a
// USHORT reference count.
// [obRowId] - offset in row data of a ULONG row
// identifier field, used for bookmarks and HROW
// identity tests.
// [obChaptRefcount] - offset in row data reserved for a
// USHORT reference count for chapters.
// [obChaptId] - offset in row data of a ULONG chapter
// identifier field. 0xFFFFFFFF if the rowset is not
// chaptered.
//
// Returns: Nothing
//
//--------------------------------------------------------------------------
CRowBufferSet::CRowBufferSet( BOOL fSequential, ULONG obRowRefcount, ULONG obRowId, ULONG obChaptRefcount, ULONG obChaptId ) : _mutex( ), _fSequential( fSequential ), _obRowRefcount( obRowRefcount ), _obRowId( obRowId ), _obChaptRefcount( obChaptRefcount ), _obChaptId( obChaptId ), _cRowBufs( 0 ), _iBufHint( 0 ), _iRowHint( 0 ) #ifdef _WIN64
, _ArrayAlloc (FALSE, FALSE, sizeof (void *), 0) #endif
#if CIDBG
, _cHintHits( 0 ), _cHintMisses( 0 ) #endif
{ // Lots of code in this file assumes the refcount is at offset 0, and
// occupies a USHORT
Win4Assert( _obRowRefcount == 0 && sizeof (CRBRefCount) == sizeof (USHORT));
Win4Assert( _obRowId != 0xFFFFFFFF || fSequential ); }
//+-------------------------------------------------------------------------
//
// Member: CRowBufferSet::~CRowBufferSet, public
//
// Synopsis: Destroy a row buffer set
//
// Returns: - nothing -
//
//--------------------------------------------------------------------------
CRowBufferSet::~CRowBufferSet( ) { CLock lock(_mutex);
#if CIDBG
tbDebugOut(( DEB_ROWBUF, " hint hits / misses: %d %d\n", _cHintHits, _cHintMisses )); #endif
for (unsigned i = 0; i < Size(); i++) { if (Get(i) != 0) { tbDebugOut(( DEB_WARN, "CRowBufferSet::~CRowBufferSet, unreleased row buffer %x\n", Get(i) ));
delete Acquire(i); } } }
//+-------------------------------------------------------------------------
//
// Member: CRowBufferSet::_FindRowBuffer, private
//
// Synopsis: Find a row buffer given an HROW
//
// Arguments: [hRow] - the row to be looked up
// [riBuf] - index to the buffer in the buffer set
// [riRow] - index to the row in the buffer
//
// Returns: CRowBuffer* - pointer to the row buffer if found, 0 otherwise
//
// Notes:
//
//--------------------------------------------------------------------------
CRowBuffer* CRowBufferSet::_FindRowBuffer( HROW hRow, unsigned & riBuf, unsigned & riRow ) { CRowBuffer* pBuffer = 0; if (IsHrowRowId()) { // Check the hints. This assumes that most hrow lookups
// will be either the same as the last requested hrow, one after the
// last requested hrow, or one before the last requested row
if ( _iBufHint < Size() && 0 != ( pBuffer = Get(_iBufHint) ) ) { if ( pBuffer->IsRowOkAndHRow( _iRowHint, hRow ) ) { #if CIDBG
_cHintHits++; #endif
riBuf = _iBufHint; riRow = _iRowHint; return pBuffer; } else if ( pBuffer->IsRowOkAndHRow( _iRowHint + 1, hRow ) ) { #if CIDBG
_cHintHits++; #endif
_iRowHint++; riBuf = _iBufHint; riRow = _iRowHint; return pBuffer; } else if ( ( _iRowHint > 0 ) && ( pBuffer->IsRowOkAndHRow( _iRowHint - 1, hRow ) ) ) { #if CIDBG
_cHintHits++; #endif
_iRowHint--; riBuf = _iBufHint; riRow = _iRowHint; return pBuffer; } }
// Lookup HROW by row id via a linear search.
for (riBuf = 0; riBuf < Size(); riBuf++) { pBuffer = Get(riBuf);
if ( ( 0 != pBuffer ) && ( pBuffer->FindHRow( riRow, hRow ) ) ) { #if CIDBG
_cHintMisses++; #endif
_iBufHint = riBuf; _iRowHint = riRow; return pBuffer; } }
pBuffer = 0; // Buffer not found
} else { //
// Row handle contains the buffer and row indices. Just unpack
// them.
//
riBuf = ((ULONG) hRow >> 20 & 0xFFF) - 1; // get buffer index
riRow = ((ULONG) hRow & 0xFFFFF) - 1; // get row index
pBuffer = Get(riBuf); }
return pBuffer; }
//+-------------------------------------------------------------------------
//
// Member: CRowBufferSet::_FindRowBufferByChapter, private
//
// Synopsis: Find a row buffer given an HCHAPTER
//
// Arguments: [hChapter] - the chapter to be looked up
// [riBuf] - index to the buffer in the buffer set
// [riRow] - index to the row in the buffer
//
// Returns: CRowBuffer* - pointer to the row buffer if found, 0 otherwise
//
// Notes:
//
//--------------------------------------------------------------------------
CRowBuffer* CRowBufferSet::_FindRowBufferByChapter( HCHAPTER hChapter, unsigned & riBuf, unsigned & riRow ) { CRowBuffer* pBuffer = 0;
Win4Assert( IsHrowRowId() && _obChaptId != 0xFFFFFFFF ); Win4Assert( DB_NULL_HCHAPTER != hChapter );
// Check the hints. This assumes that most HCHAPTER lookups
// will be either the same as the last requested HROW, one after the
// last requested HROW, or one before the last requested HROW.
if ( _iBufHint < Size() && 0 != ( pBuffer = Get(_iBufHint) ) ) { if ( pBuffer->IsRowOkAndHChapt( _iRowHint, hChapter ) ) { #if CIDBG
_cHintHits++; #endif
riBuf = _iBufHint; riRow = _iRowHint; return pBuffer; } else if ( pBuffer->IsRowOkAndHChapt( _iRowHint + 1, hChapter ) ) { #if CIDBG
_cHintHits++; #endif
_iRowHint++; riBuf = _iBufHint; riRow = _iRowHint; return pBuffer; } else if ( ( _iRowHint > 0 ) && ( pBuffer->IsRowOkAndHChapt( _iRowHint - 1, hChapter ) ) ) { #if CIDBG
_cHintHits++; #endif
_iRowHint--; riBuf = _iBufHint; riRow = _iRowHint; return pBuffer; } }
// Lookup HCHAPTER via a linear search.
for (riBuf = 0; riBuf < Size(); riBuf++) { pBuffer = Get(riBuf);
if ( ( 0 != pBuffer ) && ( pBuffer->FindHChapter( riRow, hChapter ) ) ) { #if CIDBG
_cHintMisses++; #endif
// NOTE: row hint not updated for this chapter lookup
//_iBufHint = riBuf;
//_iRowHint = riRow;
return pBuffer; } }
return 0; // Buffer not found
}
//+-------------------------------------------------------------------------
//
// Member: CRowBufferSet::Add, public
//
// Synopsis: Add a row buffer to the set
//
// Arguments: [pBuf] - a smart pointer to the buffer to be added.
// [fPossibleDuplicateHRows] - TRUE if some of the hrows may be
// duplicated in this buffer
// [pahRows] - optional pointer to array of row handles to
// be returned.
//
// Returns: Nothing, thows on error.
//
// Notes: Acquires the row buffer if successful
//
//--------------------------------------------------------------------------
VOID CRowBufferSet::Add( XPtr<CRowBuffer> & pBuf, BOOL fPossibleDuplicateHRows, HROW * pahRows ) { CLock lock(_mutex);
tbDebugOut(( DEB_ROWBUF, "CRowBufferSet::Add - new row buffer = %x\n", pBuf.GetPointer() ));
unsigned iRowBuf; if ( _cRowBufs == Size() ) iRowBuf = Size(); // There is no free element
else { for (iRowBuf = 0; iRowBuf < Size(); iRowBuf++) { if (Get(iRowBuf) == 0) break; // found a free array element.
} }
#if CIDBG
if ( iRowBuf == Size() ) { tbDebugOut(( DEB_ROWBUF, "CRowBufferSet::Add, growing row buffer array, new entry = %d\n", iRowBuf )); } #endif // CIDBG
pBuf->SetRowIdOffset( _obRowId ); if ( IsChaptered() ) pBuf->SetChapterVars( _obChaptId, _obChaptRefcount );
//
// Refcount the rows in the buffer. If there is no row identifier
// in the buffer, generate the HROW from a combination of the
// buffer number and the row index within the buffer.
// Otherwise, dereference any other occurance of the row, and
// collapse the references to the newly fetched row. Generate
// the HROW from the row identifier.
//
ULONG hRowGen = (iRowBuf+1) << 20; for (unsigned iRow = 0; iRow < pBuf->GetRowCount(); iRow++) { if (IsHrowRowId()) { HROW hRowId = pBuf->GetRowId(iRow);
CRBRefCount RowRefCount(0); CRBRefCount ChapterRefCount(0);
if ( _cRowBufs != 0 ) { unsigned iOldBuf = 0, iOldRow = 0; CRowBuffer * pOldRowBuf = _FindRowBuffer( hRowId, iOldBuf, iOldRow ); if (pOldRowBuf) { CRBRefCount OldRowRefCount; OldRowRefCount = pOldRowBuf->DereferenceRow( iOldRow ); RowRefCount.AddRefs( OldRowRefCount );
if ( IsChaptered() ) { CRBRefCount & OldChaptRefCount = pOldRowBuf->_GetChaptRefCount(iOldRow); ChapterRefCount.AddRefs( OldChaptRefCount ); }
if (pOldRowBuf->RefCount() <= 0) { //
// Deleted the last reference to the buffer. Now free
// it and its location in the array.
//
pOldRowBuf = Acquire( iOldBuf ); delete pOldRowBuf; _cRowBufs--; } } }
//
// Search for the row handle in the portion of the buffer
// already processed. This should only occur for rows which
// were fetched with GetRowsByBookmark.
//
// Chapter refcounts doen't need to be updated in this loop
// because the duplicate rows don't add to their ref. counts.
//
if ( fPossibleDuplicateHRows ) { for (unsigned iOldRow = 0; iOldRow < iRow; iOldRow++) { if ( pBuf->IsRowHRow( iOldRow, hRowId ) ) { tbDebugOut(( DEB_ROWBUF, "CRowBufferSet::Add - duplicate row: %x\n", hRowId ));
CRBRefCount OldRowRefCount; OldRowRefCount = pBuf->DereferenceRow( iOldRow ); RowRefCount.AddRefs( OldRowRefCount ); break; } } }
pBuf->InitRowRefcount(iRow, RowRefCount); if (IsChaptered()) pBuf->_GetChaptRefCount(iRow).SetRefCount( ChapterRefCount );
if (pahRows) { *pahRows++ = hRowId; } } else { CRBRefCount RowRefCount(0); pBuf->InitRowRefcount(iRow, RowRefCount); if (pahRows) { *pahRows++ = (HROW) (++hRowGen); } } }
CRowBufferArray::Add(pBuf.GetPointer(), iRowBuf); pBuf.Acquire();
_cRowBufs++; // A row buffer has been added
return; }
//+-------------------------------------------------------------------------
//
// Member: CRowBufferSet::Lookup, public
//
// Synopsis: Lookup a row by its HROW. Return data about it.
//
// Arguments: [hRow] - handle of row to be looked up
// [ppColumns] - on return, a description of the row columns
// [ppbRowData] - on return, points to row data
//
// Returns: Reference to the row buffer in which row was found.
//
// Notes: THROWs on errors.
// The row buffer set is locked only while doing the
// lookup. According to the spec, it is the responsibility
// of the consumer to ensure that only one thread will be
// using any one HROW at any one time.
//
//--------------------------------------------------------------------------
CRowBuffer & CRowBufferSet::Lookup( HROW hRow, CTableColumnSet ** ppColumns, void ** ppbRowData ) { CLock lock(_mutex);
unsigned iBuffer, iRow; CRowBuffer* pRowBuf = _FindRowBuffer(hRow, iBuffer, iRow);
if (pRowBuf == 0) QUIETTHROW( CException(DB_E_BADROWHANDLE) );
SCODE sc = pRowBuf->Lookup(iRow, ppColumns, ppbRowData ); if (FAILED(sc)) THROW( CException(sc) );
return *pRowBuf; }
//+-------------------------------------------------------------------------
//
// Member: CRowBufferSet::_LokAddRefRow, private
//
// Synopsis: Reference an individual HROW.
//
// Arguments: [hRow] - the handle of the row to be ref. counted
// [rRefCount] - reference to location where remaining ref.
// count will be stored.
// [rRowStatus] - reference to DBROWSTATUS where status will be
// stored.
//
// Returns: Nothing
//
// History: 21 Nov 1995 Alanw Created
//
//--------------------------------------------------------------------------
void CRowBufferSet::_LokAddRefRow( HROW hRow, ULONG & rRefCount, DBROWSTATUS & rRowStatus ) { unsigned iBuffer, iRow;
rRowStatus = DBROWSTATUS_S_OK; rRefCount = 0;
CRowBuffer* pRowBuf = _FindRowBuffer(hRow, iBuffer, iRow);
if (pRowBuf == 0) { rRowStatus = DBROWSTATUS_E_INVALID; return; }
pRowBuf->AddRefRow( hRow, iRow, rRefCount, rRowStatus ); Win4Assert (pRowBuf->RefCount() > 0);
return; }
//+-------------------------------------------------------------------------
//
// Member: CRowBufferSet::AddRefRows, public
//
// Synopsis: De-reference an array of HROWs.
//
// Arguments: [cRows] - the number of rows to be ref. counted
// [rghRows] - the handle of the row to be ref. counted
// [rgRefCounts] - optional array where remaining row ref.
// counts will be stored.
// [rgRowStatus] -- optional array for status of each row
//
// Returns: Nothing - throws on error
//
// History: 21 Nov 1995 Alanw Created
//
//--------------------------------------------------------------------------
void CRowBufferSet::AddRefRows( DBCOUNTITEM cRows, const HROW rghRows [], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[] ) { CLock lock(_mutex);
ULONG cError = 0;
if (rghRows == 0 && cRows != 0) THROW( CException( E_INVALIDARG ));
for (unsigned i=0; i<cRows; i++) { TRY {
ULONG ulRefCount; DBROWSTATUS RowStatus;
_LokAddRefRow(rghRows[i], ulRefCount, RowStatus); if (rgRefCounts) rgRefCounts[i] = ulRefCount;
if (rgRowStatus) rgRowStatus[i] = RowStatus;
if (DBROWSTATUS_S_OK != RowStatus) cError++; } CATCH( CException, e ) { if (DB_E_BADROWHANDLE == e.GetErrorCode()) { if (rgRowStatus) rgRowStatus[i] = DBROWSTATUS_E_INVALID;
if (rgRefCounts) rgRefCounts[i] = 0;
cError++; } else { RETHROW(); } } END_CATCH;
} if (cError) THROW( CException( (cError==cRows) ? DB_E_ERRORSOCCURRED : DB_S_ERRORSOCCURRED ));
return; }
//+-------------------------------------------------------------------------
//
// Member: CRowBufferSet::_LokReleaseRow, private
//
// Synopsis: De-reference an individual HROW.
//
// Arguments: [hRow] - the handle of the row to be released
// [rRefCount] - reference to location where remaining ref.
// count will be stored.
// [rRowStatus] - reference to DBROWSTATUS where status will be
// stored.
//
// Returns: Nothing
//
//--------------------------------------------------------------------------
void CRowBufferSet::_LokReleaseRow( HROW hRow, ULONG & rRefCount, DBROWSTATUS & rRowStatus ) { unsigned iBuffer, iRow; CRowBuffer* pRowBuf = _FindRowBuffer(hRow, iBuffer, iRow);
rRowStatus = DBROWSTATUS_S_OK; rRefCount = 0;
if (pRowBuf == 0) { rRowStatus = DBROWSTATUS_E_INVALID; return; }
BOOL fRemoveCopies = pRowBuf->ReleaseRow( hRow, iRow, rRefCount, rRowStatus );
if (pRowBuf->RefCount() <= 0) { //
// Deleted the last reference to the buffer. Now free it
// and its location in the array.
//
Win4Assert( pRowBuf == Get( iBuffer ) ); pRowBuf = Acquire( iBuffer ); Win4Assert( 0 == Get( iBuffer ) ); delete pRowBuf;
_cRowBufs--; // A row buffer has been removed
}
if (fRemoveCopies) { //
// The last reference to a row which also exists in other row
// buffers was released. Finally get rid of the row in the
// other buffer(s).
//
Win4Assert(IsHrowRowId());
// Lookup HROW by row id via a linear search.
for (unsigned iBuf = Size(); iBuf > 0; iBuf--) { unsigned iRow; CRowBuffer* pBuffer = Get(iBuf-1);
if ( ( 0 != pBuffer ) && ( pBuffer->FindHRow( iRow, hRow, TRUE ) ) ) { ULONG cRefs; DBROWSTATUS RowStat;
pBuffer->ReleaseRow( hRow, iRow, cRefs, RowStat ); if (pBuffer->RefCount() <= 0) { //
// Deleted the last reference to the buffer. Now free it
// and its location in the array.
//
pBuffer = Acquire( iBuf-1); delete pBuffer; _cRowBufs--; // A row buffer has been removed
//
// Start scanning buffers again
//
iBuf = Size() + 1; } } } } return; }
//+-------------------------------------------------------------------------
//
// Member: CRowBufferSet::ReleaseRows, public
//
// Synopsis: De-reference an array of HROWs.
//
// Arguments: [cRows] - the number of rows to be released
// [rghRows] - the handle of the row to be released
// [rgRefCounts] - optional array where remaining row ref.
// counts will be stored.
// [rgRowStatus] -- optional array for status of each row
//
// Returns: SCODE - result status, usually one of S_OK,
// DB_S_ERRORSOCCURRED, or DB_E_ERRORSOCCURRED
//
// Notes:
//
//--------------------------------------------------------------------------
SCODE CRowBufferSet::ReleaseRows( DBCOUNTITEM cRows, const HROW rghRows [], DBREFCOUNT rgRefCounts[], DBROWSTATUS rgRowStatus[] ) { CLock lock(_mutex);
ULONG cError = 0;
if (rghRows == 0 && cRows != 0) THROW( CException( E_INVALIDARG ));
for (unsigned i=0; i<cRows; i++) { TRY { ULONG ulRefCount; DBROWSTATUS RowStatus;
_LokReleaseRow(rghRows[i], ulRefCount, RowStatus);
if (rgRefCounts) rgRefCounts[i] = ulRefCount;
if (rgRowStatus) rgRowStatus[i] = RowStatus;
if (DBROWSTATUS_S_OK != RowStatus) cError++; } CATCH( CException, e ) { if (DB_E_BADROWHANDLE == e.GetErrorCode()) { if (rgRowStatus) rgRowStatus[i] = DBROWSTATUS_E_INVALID;
if (rgRefCounts) rgRefCounts[i] = 0;
cError++; } else { RETHROW(); } } END_CATCH; }
SCODE scResult = cError ? ( (cError==cRows) ? DB_E_ERRORSOCCURRED : DB_S_ERRORSOCCURRED ) : S_OK;
return scResult; }
//+-------------------------------------------------------------------------
//
// Member: CRowBufferSet::CheckAllHrowsReleased, public
//
// Synopsis: Check that there are no outstanding HROWs. Used by
// the sequential rowset to check its strict sequential
// semantics.
//
// Arguments: - none -
//
// Returns: Nothing
//
// Notes: THROWs DB_E_ROWSNOTRELEASED if any row buffers are
// still held.
//
//--------------------------------------------------------------------------
VOID CRowBufferSet::CheckAllHrowsReleased( ) { CLock lock(_mutex);
if ( _cRowBufs != 0 ) { tbDebugOut(( DEB_WARN, "CRowBufferSet::CheckAllHrowsReleased, unreleased row buffer(s)\n" ));
QUIETTHROW( CException(DB_E_ROWSNOTRELEASED) ); } }
//+-------------------------------------------------------------------------
//
// Member: CRowBufferSet::AddRefChapter, private
//
// Synopsis: Reference an individual HCHAPTER.
//
// Arguments: [hChapter] - the handle of the Chapter to be ref. counted
// [pcRefCount] - optional pointer where remaining ref.
// count will be stored.
//
// Returns: Nothing - throws on error
//
// History: 16 Mar 1999 Alanw Created
//
//--------------------------------------------------------------------------
void CRowBufferSet::AddRefChapter( HCHAPTER hChapter, ULONG * pcRefCount ) { CLock lock(_mutex);
Win4Assert( _obChaptRefcount != 0xFFFFFFFF ); unsigned iBuffer, iRow;
CRowBuffer* pRowBuf = _FindRowBufferByChapter(hChapter, iBuffer, iRow);
if (pRowBuf == 0) { THROW(CException( DB_E_BADCHAPTER )); return; }
ULONG cRefCount = 0;
pRowBuf->AddRefChapter( iRow, cRefCount ); if ( 0 != pcRefCount ) *pcRefCount = cRefCount;
return; }
//+-------------------------------------------------------------------------
//
// Member: CRowBufferSet::ReleaseChapter, private
//
// Synopsis: Release an individual HCHAPTER.
//
// Arguments: [hChapter] - the handle of the Chapter to be released
// [pcRefCount] - optional pointer where remaining ref.
// count will be stored.
//
// Returns: Nothing - throws on error
//
// History: 16 Mar 1999 Alanw Created
//
//--------------------------------------------------------------------------
void CRowBufferSet::ReleaseChapter( HCHAPTER hChapter, ULONG * pcRefCount ) { CLock lock(_mutex);
Win4Assert( _obChaptRefcount != 0xFFFFFFFF ); unsigned iBuffer, iRow;
CRowBuffer* pRowBuf = _FindRowBufferByChapter(hChapter, iBuffer, iRow);
if (pRowBuf == 0) { THROW(CException( DB_E_BADCHAPTER )); return; }
ULONG cRefCount = 0;
pRowBuf->ReleaseChapter( iRow, cRefCount ); if ( 0 != pcRefCount ) *pcRefCount = cRefCount;
return; }
//+-------------------------------------------------------------------------
//
// Member: CRowBuffer constructor, public
//
// Synopsis: Create a row buffer
//
// Arguments: [rColumns] - a description of the row columns
// [cbRowWidth] - row data length per row
// [cRows] - number of rows represented in the row data
// [rAlloc] - allocator xptr to be acquired
//
// Returns: Nothing
//
//--------------------------------------------------------------------------
CRowBuffer::CRowBuffer( CTableColumnSet& rColumns, ULONG cbRowWidth, ULONG cRows, XPtr<CFixedVarAllocator> & rAlloc ) : _cRows( cRows ), _cReferences( 0 ), _cbRowWidth( cbRowWidth ), _Columns( rColumns ), _fQuickPROPID(TRUE), _pbRowData( rAlloc->FirstRow() ), _obRowId( 0 ), _Alloc( rAlloc.Acquire() ), _aDeferredValues( 0 ) { //
// OPTIMIZATION - See if we can support a quick lookup of PROPIDs.
//
for ( unsigned i = 0; i < _Columns.Count(); i++ ) { CTableColumn * pCol = _Columns.Get(i); if ( pCol && i != pCol->GetPropId()-1 ) { _fQuickPROPID = FALSE; break; } } }
//+-------------------------------------------------------------------------
//
// Member: CRowBuffer destructor, public
//
// Synopsis: Destroy a row buffer
//
//+-------------------------------------------------------------------------
CRowBuffer::~CRowBuffer( ) { }
//+-------------------------------------------------------------------------
//
// Member: CRowBuffer::_IndexRow, private
//
// Synopsis: Find a row in a row buffer given its index
//
// Arguments: [iRow] - the index of the row to be looked up
// [fVerifyRefcnt] - if TRUE, the row's refcount will be
// checked for non-zero.
//
// Returns: BYTE* - the address of the row's data
//
// Notes: Throws DB_E_BADROWHANDLE if the row index is out of
// range, or if the row is not referenced.
//
//--------------------------------------------------------------------------
BYTE* CRowBuffer::_IndexRow( unsigned iRow, int fVerifyRefcnt ) const { if (iRow >= _cRows) QUIETTHROW( CException( DB_E_BADROWHANDLE ) );
BYTE* pbRow = _pbRowData + (iRow * _cbRowWidth);
// Is the row still referenced?
if ( fVerifyRefcnt && ((CRBRefCount *) (pbRow))->GetRefCount() == 0) QUIETTHROW( CException( DB_E_BADROWHANDLE ) );
return pbRow; }
//+-------------------------------------------------------------------------
//
// Member: CRowBuffer::_GetRowRefCount, private
//
// Synopsis: Return a reference to the refcount of a row.
//
// Arguments: [iRow] - the index of the row to be looked up
//
// Returns: CRBRefCount& - the address of the row's refcount
//
// Notes: Throws DB_E_BADROWHANDLE if the row index is out of
// range.
//
//--------------------------------------------------------------------------
inline CRBRefCount & CRowBuffer::_GetRowRefCount( unsigned iRow ) const { CRBRefCount * pbRowRefCount = (CRBRefCount *)_IndexRow( iRow, FALSE );
return *pbRowRefCount; }
//+-------------------------------------------------------------------------
//
// Member: CRowBuffer::_GetChaptRefCount, private
//
// Synopsis: Return a reference to the refcount of a row.
//
// Arguments: [iRow] - the index of the row to be looked up
//
// Returns: CRBRefCount& - the address of the row's refcount
//
// Notes: Throws DB_E_BADROWHANDLE if the row index is out of
// range.
//
//--------------------------------------------------------------------------
inline CRBRefCount & CRowBuffer::_GetChaptRefCount( unsigned iRow ) const { Win4Assert( _obChaptRefcount != 0xFFFFFFFF ); CRBRefCount * pbRowRefCount = (CRBRefCount *) (_IndexRow( iRow, FALSE ) + _obChaptRefcount);
return *pbRowRefCount; }
//+-------------------------------------------------------------------------
//
// Member: CRowBuffer::GetRowId, public
//
// Synopsis: Lookup a row's ID.
//
// Arguments: [iRow] - index of row to be looked up
//
// Returns: HROW - the row's Row ID.
//
// Notes: _IndexRow is called without ref. count verification
// for the case of CRowBufferSet::Add where new buffer
// has its ref. counts initialized.
//
//--------------------------------------------------------------------------
inline HROW CRowBuffer::GetRowId( unsigned iRow ) const { Win4Assert( _obRowId <= _cbRowWidth - sizeof (ULONG) ); HROW* phRowId = (HROW *) ( _IndexRow(iRow, FALSE) + _obRowId ); return *(HROW UNALIGNED *) phRowId; }
//+-------------------------------------------------------------------------
//
// Member: CRowBuffer::Lookup, public
//
// Synopsis: Lookup a row by its HROW. Return data about it.
//
// Arguments: [iRow] - index of row to be looked up
// [ppColumns] - on return, a description of the row columns
// [ppbRowData] - on return, points to row data
// [fValidate] - whether IndexRow should validate the refcount
//
// Returns: SCODE - status of lookup, DB_E_BADROWHANDLE for
// an HROW that could not be found in the buffer
//
// Notes:
//
//--------------------------------------------------------------------------
SCODE CRowBuffer::Lookup( unsigned iRow, CTableColumnSet ** ppColumns, void ** ppbRowData, BOOL fValidate ) const { *ppbRowData = _IndexRow( iRow, fValidate ); *ppColumns = &_Columns;
return S_OK; }
//+-------------------------------------------------------------------------
//
// Member: CRowBuffer::AddRefRow, public
//
// Synopsis: Reference an HROW.
//
// Arguments: [hRow] - hrow of row to be ref. counted
// [iRow] - the index of the row to be ref. counted
// [rcRef] - on return, remaining ref. count
// of the row.
// [rRowStatus] - reference to DBROWSTATUS where status will be
// stored.
//
// Returns: Nothing - throws DB_E_BADROWHANDLE if row couldn't be
// found.
//
// History: 21 Nov 1995 Alanw Created
//
//--------------------------------------------------------------------------
void CRowBuffer::AddRefRow( HROW hRow, unsigned iRow, ULONG & rcRef, DBROWSTATUS & rRowStatus ) { CRBRefCount & rRefCount = _GetRowRefCount(iRow);
if (rRefCount.GetRefCount() == 0) { rRowStatus = DBROWSTATUS_E_INVALID; rcRef = 0; } else { rRefCount.IncRefCount(); rcRef = rRefCount.GetRefCount(); } return; }
//+-------------------------------------------------------------------------
//
// Member: CRowBuffer::ReleaseRow, public
//
// Synopsis: De-reference an HROW.
//
// Arguments: [hRow] - hrow of row to be released
// [iRow] - the index of the row to be released
// [rcRef] - on return, remaining ref. count
// of the row.
// [rRowStatus] - reference to DBROWSTATUS where status will be
// stored.
//
// Returns: BOOL - if TRUE on return, there are copies of the HROW
// with byref data. Delete those as well
// since this is the last reference to the HROW.
//
// Notes:
//
// History: 20 Feb 1995 Alanw Added individual row refcounts
//
//--------------------------------------------------------------------------
BOOL CRowBuffer::ReleaseRow( HROW hRow, unsigned iRow, ULONG & rcRef, DBROWSTATUS & rRowStatus ) { BOOL fRemoveCopies = FALSE; CRBRefCount & rRefCount = _GetRowRefCount(iRow);
if ( rRefCount.GetRefCount() == 0 && ! rRefCount.HasByrefData() ) { rRowStatus = DBROWSTATUS_E_INVALID; rcRef = 0; } else { //
// This might be a zero ref-count row with the ByrefData bit set.
//
if (rRefCount.GetRefCount() > 0) { rRefCount.DecRefCount(); }
if (rRefCount.GetRefCount() == 0) { if (rRefCount.HasByrefCopy()) fRemoveCopies = TRUE;
// Free any deferred values hanging around for this row.
// Better now than at row buffer destruction time.
for ( unsigned x = 0; x < _aDeferredValues.Count(); x++ ) { if ( hRow == _aDeferredValues[ x ].GetHRow() ) { Win4Assert(rRefCount.HasByrefData()); _aDeferredValues[ x ].Release(); } }
_cReferences--; CRBRefCount ZeroRefCount(0); rRefCount = ZeroRefCount; } rcRef = rRefCount.GetRefCount(); } return fRemoveCopies; }
//+-------------------------------------------------------------------------
//
// Member: CRowBuffer::ReferenceChapter, public
//
// Synopsis: Reference a chapter handle. Used by accessors.
//
// Arguments: [pbRow] - pointer to the row within the row buffer
//
// Returns: Nothing
//
// History: 17 Mar 1999 Alanw Created
//
//--------------------------------------------------------------------------
void CRowBuffer::ReferenceChapter( BYTE * pbRow ) { Win4Assert( _obChaptRefcount != 0xFFFFFFFF ); CRBRefCount & rRefCount = *(CRBRefCount *) (pbRow + _obChaptRefcount);
Win4Assert( ! rRefCount.HasByrefCopy() && ! rRefCount.HasByrefData() );
rRefCount.IncRefCount(); return; }
//+-------------------------------------------------------------------------
//
// Member: CRowBuffer::AddRefChapter, public
//
// Synopsis: Reference a chapter handle
//
// Arguments: [iRow] - the index of the row with chapter to be released
// [rcRef] - on return, remaining ref. count of the chapter.
//
// Returns: Nothing
//
// History: 17 Mar 1999 Alanw Created
//
//--------------------------------------------------------------------------
void CRowBuffer::AddRefChapter( unsigned iRow, ULONG & rcRef ) { CRBRefCount & rRefCount = _GetChaptRefCount(iRow);
Win4Assert( rRefCount.GetRefCount() > 0 && ! rRefCount.HasByrefCopy() && ! rRefCount.HasByrefData() ); if (rRefCount.GetRefCount() == 0) { rcRef = 0; } else { rRefCount.IncRefCount(); rcRef = rRefCount.GetRefCount(); } return; }
//+-------------------------------------------------------------------------
//
// Member: CRowBuffer::ReleaseChapter, public
//
// Synopsis: De-reference a chapter handle
//
// Arguments: [iRow] - the index of the row with chapter to be released
// [rcRef] - on return, remaining ref. count of the chapter.
//
// Returns: Nothing
//
// History: 17 Mar 1999 Alanw Created
//
//--------------------------------------------------------------------------
void CRowBuffer::ReleaseChapter( unsigned iRow, ULONG & rcRef ) { CRBRefCount & rRefCount = _GetChaptRefCount(iRow);
if ( rRefCount.GetRefCount() == 0 ) { rcRef = 0; THROW( CException( DB_E_BADCHAPTER ) ); } else { rRefCount.DecRefCount(); rcRef = rRefCount.GetRefCount(); } return; }
//+-------------------------------------------------------------------------
//
// Member: CRowBuffer::InitRowRefcount, public
//
// Synopsis: Set initial reference count on an HROW.
//
// Arguments: [iRow] - the index of the row within the buffer
// [OtherRefs] - reference count transferred from
// another row.
//
// Returns: Nothing
//
// Notes:
//
// History: 20 Feb 1995 Alanw Created
//
//--------------------------------------------------------------------------
void CRowBuffer::InitRowRefcount( unsigned iRow, CRBRefCount & OtherRefs ) { CRBRefCount RefCount( OtherRefs.GetRefCount() ); RefCount.IncRefCount();
if ( OtherRefs.HasByrefData() || OtherRefs.HasByrefCopy() ) RefCount.SetByrefCopy();
CRBRefCount & rRef = _GetRowRefCount(iRow);
rRef = RefCount; _cReferences++; return; }
//+-------------------------------------------------------------------------
//
// Member: CRowBuffer::DereferenceRow, public
//
// Synopsis: Remove all references from a row
//
// Arguments: [iRow] - the index of the row within the buffer
//
// Returns: CRBRefCount - reference count of row
//
// Notes: If the client had retrieved a pointer into the rowbuffer,
// the row stays around with a zero ref. count and will
// be finally dereferenced when all references to all copies
// of the row are released.
//
// History: 22 Mar 1995 Alanw Created
//
//--------------------------------------------------------------------------
CRBRefCount CRowBuffer::DereferenceRow( unsigned iRow ) { CRBRefCount & rRef = _GetRowRefCount(iRow); CRBRefCount OldRef = rRef; CRBRefCount NewRef(0);
Win4Assert(OldRef.GetRefCount() != 0 && _cReferences > 0);
if ( OldRef.HasByrefData() ) NewRef.SetByrefData(); else _cReferences--;
rRef = NewRef; return OldRef; }
//+-------------------------------------------------------------------------
//
// Member: CRowBuffer::FindHRow, public
//
// Synopsis: Looks for an hrow in the row buffer and returns its index
//
// Arguments: [riRow] - returns the index of hRow's row if found
// [hRow] - HROW to be found
// [fFindByrefData] - if TRUE, zero ref. rows with byref data
// are found.
//
// Returns: BOOL - TRUE if found, FALSE otherwise
//
// History: 16 Aug 1995 dlee Created
//
//--------------------------------------------------------------------------
BOOL CRowBuffer::FindHRow( unsigned & riRow, HROW hRow, BOOL fFindByrefData ) const { BYTE* pbRow = _pbRowData;
for ( unsigned iRow = 0; iRow < GetRowCount(); iRow++, pbRow += _cbRowWidth ) { // refcount is the first USHORT in each row
CRBRefCount * pRefCount = (CRBRefCount *) pbRow;
//
// HROW == 64 bits on Sundown, but we know HROWs are just
// workids that fit in a ULONG.
//
if ( (ULONG) hRow == ( * (ULONG *) ( pbRow + _obRowId ) ) ) { if ( ( 0 != pRefCount->GetRefCount() ) || (fFindByrefData && pRefCount->HasByrefData()) ) { riRow = iRow; return TRUE; } } }
return FALSE; }
//+-------------------------------------------------------------------------
//
// Member: CRowBuffer::FindHChapter, public
//
// Synopsis: Looks for an HCHAPTER in the row buffer and returns its index
//
// Arguments: [riRow] - returns the index of hChapter's row if found
// [hChapter] - HCHAPTER to be found
//
// Returns: BOOL - TRUE if found, FALSE otherwise
//
// History: 17 Mar 1999 AlanW Created
// 10 Nov 1999 KLam Changed HCHAPTER cast to CI_TBL_CHAPT
//
//--------------------------------------------------------------------------
BOOL CRowBuffer::FindHChapter( unsigned & riRow, HCHAPTER hChapter ) const { BYTE* pbRow = _pbRowData;
Win4Assert( IsChaptered() ); for ( unsigned iRow = 0; iRow < GetRowCount(); iRow++, pbRow += _cbRowWidth ) { // refcount is the first USHORT in each row
CRBRefCount * pRefCount = (CRBRefCount *) pbRow;
if ( hChapter == ( * (CI_TBL_CHAPT *) ( pbRow + _obChaptId ) ) ) { if ( ( 0 != pRefCount->GetRefCount() ) // || (fFindByrefData && pRefCount->HasByrefData())
) { riRow = iRow; return TRUE; } } }
return FALSE; }
//+-------------------------------------------------------------------------
//
// Member: CDeferredValue::Release, public
//
// Synopsis: Frees a deferred value
//
// History: 4 Aug 1995 dlee Created
//
//--------------------------------------------------------------------------
void CDeferredValue::Release() { if ( 0 != _hrow ) { PropVariantClear( &_var ); _hrow = 0; } } //Release
|