windows-nt/Source/XPSP1/NT/inetsrv/query/h/rowbuf.hxx
2020-09-26 16:20:57 +08:00

469 lines
14 KiB
C++

//+-------------------------------------------------------------------------
//
// 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 <tblalloc.hxx>
#include <tablecol.hxx>
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<CFixedVarAllocator> & 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<CFixedVarAllocator> _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<CDeferredValue> _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<CRowBuffer> & 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
};