//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1994 - 1999. // // File: rowbuf.hxx // // Contents: Declaration of the row buffer classes, used for HROW // buffering at the interface level. // // Classes: CRowBuffer // CRowBufferSet // CDeferredValue // CRBRefCount // // History: 22 Nov 1994 AlanW Created // //-------------------------------------------------------------------------- #pragma once #include #include class CTableColumnSet; //+------------------------------------------------------------------------- // // Class: CDeferredValue // // Purpose: Holds a value that is not in the row buffer because the value // was deferred. The row buffer must free these values because // the client asked for them DBTYPE_BYREF or DBTYPE_VECTOR with // DBMEMOWNER_PROVIDEROWNED, so they must exist until the // HROW goes away. // // History: 4 Aug 1995 dlee Created // //-------------------------------------------------------------------------- class CDeferredValue { public: CDeferredValue( HROW hrow, PROPVARIANT & var ) : _hrow( hrow ), _var( var ) { } CDeferredValue() : _hrow( 0 ) { } ~CDeferredValue() { Release(); } void operator= ( CDeferredValue & val ) { _hrow = val._hrow; _var = val._var; val._hrow = 0; } HROW GetHRow() { return _hrow; } void Release(); private: PROPVARIANT _var; // data that is deferred HROW _hrow; // hrow to which the allocation belongs }; //+------------------------------------------------------------------------- // // Class: CRBRefCount // // Purpose: An HROW reference count in a row buffer. // // Notes: The ref. count occupies a USHORT at the beginning of the // memory for the row. // // History: 29 May 1997 AlanW Created // //-------------------------------------------------------------------------- const unsigned maxRowRefCount = 0x3FFF; const unsigned eHasByrefData = 0x4000; // GetData has handed out ptr in buffer const unsigned eHasByrefCopy = 0x8000; // a copy of row exists with eHasByrefData class CRBRefCount { public: USHORT GetRefCount() const { return _usRef & maxRowRefCount; } void SetRefCount( CRBRefCount & Ref ) { _usRef = Ref._usRef; } void SetRefCount(unsigned cRef) { _usRef = (_usRef & ~maxRowRefCount) | cRef; } void IncRefCount() { unsigned cRef = GetRefCount(); if (cRef < maxRowRefCount) cRef++; SetRefCount( cRef ); } void DecRefCount() { unsigned cRef = GetRefCount(); Win4Assert(cRef > 0); if (cRef > 0) cRef--; SetRefCount( cRef ); } void AddRefs( CRBRefCount & Ref ) { unsigned cRef = GetRefCount(); if ( (cRef + Ref.GetRefCount()) < maxRowRefCount) cRef += Ref.GetRefCount(); else cRef = maxRowRefCount; SetRefCount( cRef ); if ( Ref.HasByrefData() ) SetByrefData(); if ( Ref.HasByrefCopy() ) SetByrefCopy(); } BOOL HasByrefData() { return (_usRef & eHasByrefData) != 0; } BOOL HasByrefCopy() { return (_usRef & eHasByrefCopy) != 0; } void SetByrefData() { _usRef |= eHasByrefData; } void SetByrefCopy() { _usRef |= eHasByrefCopy; } CRBRefCount( unsigned cRef = 0 ) : _usRef( (WORD)cRef ) { } CRBRefCount( CRBRefCount & Ref ) : _usRef( Ref._usRef ) { } private: USHORT _usRef; }; //+------------------------------------------------------------------------- // // Class: CRowBuffer // // Purpose: A row buffer in the client process. This // provides the interface to HROWs for OLE-DB. // // Interface: // // History: 11 Nov 99 KLam Changed cast in IsRowHChapt for Win64 // //-------------------------------------------------------------------------- class CRowBuffer { friend class CRowBufferSet; public: CRowBuffer( CTableColumnSet& rColumns, ULONG cbRowWidth, ULONG cRows, XPtr & rAlloc ); ~CRowBuffer(); SCODE Lookup( unsigned iRow, CTableColumnSet ** ppColumns, void ** ppbRowData, BOOL fValidate = TRUE ) const; void AddRefRow( HROW hRow, unsigned iRow, ULONG & rRefCount, DBROWSTATUS & rRowStatus ); BOOL ReleaseRow( HROW hRow, unsigned iRow, ULONG & rRefCount, DBROWSTATUS & rRowStatus ); void ReferenceChapter( BYTE * pbRow ); void AddRefChapter( unsigned iRow, ULONG & rRefCount ); void ReleaseChapter( unsigned iRow, ULONG & rRefCount ); inline void InitRowRefcount( unsigned iRow, CRBRefCount & OtherRefs ); CRBRefCount DereferenceRow( unsigned iRow ); HROW GetRowId(unsigned iRow) const; ULONG GetRowWidth(void) const { return _cbRowWidth; } ULONG GetRowCount(void) const { return _cRows; } void SetRowIdOffset( ULONG obRowId ) { _obRowId = obRowId; } void SetChapterVars( ULONG obChaptId, ULONG obChaptRefcnt ) { _obChaptId = obChaptId; _obChaptRefcount = obChaptRefcnt; } LONG RefCount(void) const { return _cReferences; } void LokReference() { _cReferences++; } void AddDeferredValue( CDeferredValue & val ) { Win4Assert( ciIsValidPointer( _aDeferredValues.GetPointer() ) ); _aDeferredValues[ _aDeferredValues.Count() ] = val; Win4Assert( ciIsValidPointer( _aDeferredValues.GetPointer() ) ); } BOOL FindHRow( unsigned &riRow, HROW hRow, BOOL fFindByrefData = FALSE ) const; BOOL FindHChapter( unsigned &riRow, HCHAPTER hChapter ) const; BOOL IsRowHRow( unsigned iRow, HROW hRow ) const { BYTE* pbRow = _pbRowData + ( iRow * _cbRowWidth ); // refcount is the first USHORT in each row return ( ( 0 != ((CRBRefCount *) pbRow)->GetRefCount() ) && ( hRow == ( * (HROW UNALIGNED *) ( pbRow + _obRowId ) ) ) ); } BOOL IsRowOkAndHRow( unsigned iRow, HROW hRow ) const { if ( iRow >= GetRowCount() ) return FALSE; return IsRowHRow( iRow, hRow ); } BOOL IsRowHChapt( unsigned iRow, HCHAPTER hChapt ) const { BYTE* pbRow = _pbRowData + ( iRow * _cbRowWidth ); // refcount is the first USHORT in each row return ( ( 0 != ((CRBRefCount *) pbRow)->GetRefCount() ) && ( hChapt == ( * (CI_TBL_CHAPT *) ( pbRow + _obChaptId ) ) ) ); } BOOL IsRowOkAndHChapt( unsigned iRow, HCHAPTER hChapt ) const { if ( iRow >= GetRowCount() ) return FALSE; return IsRowHChapt( iRow, hChapt ); } CTableColumn * Find( PROPID propid ) const { if ( _fQuickPROPID && propid <= _Columns.Count() ) { Win4Assert( 0 != propid ); return _Columns.Get( propid-1 ); } else { return _Columns.Find( propid ); } } void SetByrefData( BYTE * pbRow ) { CRBRefCount * pRefCount = (CRBRefCount *) pbRow; pRefCount->SetByrefData(); } private: inline BOOL IsChaptered( ) const { return _obChaptId != 0xFFFFFFFF; } inline BYTE* _IndexRow( unsigned iRow, int fVerifyRefcnt = TRUE ) const; CRBRefCount & _GetRowRefCount( unsigned iRow ) const; CRBRefCount & _GetChaptRefCount( unsigned iRow ) const; LONG _cReferences; // number of referenced rows in buffer ULONG _cRows; // number of rows in this buffer ULONG _cbRowWidth; // size of each row BYTE* _pbRowData; // pointer to row data ULONG _obRowId; // offset to row ID ULONG _obChaptId; // offset to chapter ID ULONG _obChaptRefcount; // offset to chapter ref. count XPtr _Alloc; // allocator holding row data CTableColumnSet& _Columns; // column descriptions // Optimization to speed up the lookup of PROPIDs BOOL _fQuickPROPID; // Set to TRUE if PropIds can be looked // up quickly CDynArrayInPlaceNST _aDeferredValues; // deferred byref data }; DECL_DYNARRAY( CRowBufferArray, CRowBuffer ) //+------------------------------------------------------------------------- // // Class: CRowBufferSet // // Purpose: A set of row buffers in the client process. This // provides the interface to HROWs for OLE-DB. // // Interface: // //-------------------------------------------------------------------------- class CRowBufferSet : public CRowBufferArray { public: CRowBufferSet( BOOL fSequential, ULONG obRowRefcount, ULONG obRowId, ULONG obChaptRefcount, ULONG obChaptId ); ~CRowBufferSet(); CRowBuffer &Lookup( HROW hRow, CTableColumnSet ** ppColumns, void ** ppbRowData ); void Add( XPtr & pBuf, BOOL fPossibleDuplicateHRows, HROW * pahRows = 0 ); void AddRefRows( DBCOUNTITEM cRows, const HROW rghRows [], DBREFCOUNT rgRefCounts[] = 0, DBROWSTATUS rgRowStatus[] = 0 ); SCODE ReleaseRows( DBCOUNTITEM cRows, const HROW rghRows [], DBREFCOUNT rgRefCounts[] = 0, DBROWSTATUS rgRowStatus[] = 0 ); void CheckAllHrowsReleased( ); void AddRefChapter( HCHAPTER hChapter, ULONG * pcRefCount ); void ReleaseChapter( HCHAPTER hChapter, ULONG * pcRefCount ); CMutexSem & GetBufferLock( ) { return _mutex; } BOOL IsChaptered( ) const { return _obChaptId != 0xFFFFFFFF; } #ifdef _WIN64 CFixedVarAllocator * GetArrayAlloc () { return &_ArrayAlloc; } #endif private: void _LokAddRefRow( HROW hRow, ULONG & rRefCount, DBROWSTATUS & rRowStatus ); void _LokReleaseRow( HROW hRow, ULONG & rRefCount, DBROWSTATUS & rRowStatus ); inline BOOL IsHrowRowId( ) const { return ! _fSequential; } CRowBuffer* _FindRowBuffer( HROW hRow, unsigned & iBuf, unsigned & iRow ); CRowBuffer* _FindRowBufferByChapter( HCHAPTER hChapter, unsigned & iBuf, unsigned & iRow ); BOOL _fSequential; ULONG _obRowRefcount; // offset of row reference cnt in bufs ULONG _obRowId; // offset of row identifier in buffers ULONG _obChaptRefcount; // offset of chapter reference cnt in bufs ULONG _obChaptId; // offset of chapter identifier in buffers ULONG _cRowBufs; // Count of row buffers in this set #ifdef _WIN64 CFixedVarAllocator _ArrayAlloc; // Used for arrays of pointers in 64c -> 32s #endif // Hints for the next lookup of an hrow unsigned _iBufHint; unsigned _iRowHint; #if CIDBG unsigned _cHintHits; unsigned _cHintMisses; #endif CMutexSem _mutex; // serialize on buffer set operations };