800 lines
23 KiB
C++
800 lines
23 KiB
C++
/////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft WMIOLE DB Provider
|
|
// (C) Copyright 1999 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// Hashing routines for row manipulation.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
#include "headers.h"
|
|
#include "hashtbl.h"
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
// Constructor
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
_COLUMNDATA::_COLUMNDATA()
|
|
{
|
|
dwLength = 0;
|
|
dwStatus = 0;
|
|
dwType = 0;
|
|
pbData= NULL;
|
|
}
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
// Destructor
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
_COLUMNDATA::~_COLUMNDATA()
|
|
{
|
|
CDataMap Map;
|
|
Map.FreeData(dwType,pbData);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
// Function to set column information for the current column
|
|
// NTRaid:111827 111828
|
|
// 06/07/00
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
HRESULT _COLUMNDATA::SetData(CVARIANT & vVar , DWORD dwColType )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CDataMap Map;
|
|
// NTRaid:111828
|
|
// 06/13/00
|
|
WORD wType = -1;
|
|
// NTRaid:111827
|
|
// 06/13/00
|
|
DWORD dwFlags = 0;
|
|
|
|
dwStatus = E_UNEXPECTED;
|
|
|
|
//=================================================================
|
|
// This will set the type of the column in _COLUMNDATA
|
|
//=================================================================
|
|
hr = Map.MapCIMTypeToOLEDBType(vVar.GetType(),wType,dwLength,dwFlags);
|
|
dwType = wType;
|
|
|
|
if( dwColType == CIM_DATETIME || dwColType == DBTYPE_DBTIMESTAMP)
|
|
{
|
|
dwType = CIM_DATETIME;
|
|
}
|
|
|
|
//=================================================================================
|
|
// This is done so as AllocateAndMapCIMTypeToOLEDBType should convert from
|
|
// Variant DATE format to DBTIMESTAMP format
|
|
//=================================================================================
|
|
if( vVar.GetType() == VT_DATE)
|
|
{
|
|
dwType = VT_DATE;
|
|
}
|
|
|
|
if( dwColType == VT_VARIANT)
|
|
{
|
|
dwType = (DBTYPE)dwColType;
|
|
}
|
|
|
|
if(dwColType == CIM_IUNKNOWN)
|
|
{
|
|
dwType = CIM_IUNKNOWN;
|
|
}
|
|
|
|
hr = Map.AllocateAndMapCIMTypeToOLEDBType(vVar,pbData,dwType, dwLength,dwFlags);
|
|
if(SUCCEEDED(hr)){
|
|
//=============================================================================
|
|
// SetData returns the status of the Data setting if it has not failed
|
|
//=============================================================================
|
|
dwStatus = hr;
|
|
|
|
if((dwColType == (CIM_DATETIME | CIM_FLAG_ARRAY)) || (dwColType == (DBTYPE_DBTIMESTAMP | CIM_FLAG_ARRAY)) )
|
|
{
|
|
dwType = (DBTYPE)dwColType;
|
|
}
|
|
else
|
|
if(dwType == CIM_IUNKNOWN)
|
|
{
|
|
dwType = DBTYPE_IUNKNOWN;
|
|
}
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
// Function to reset the column data. This frees column data
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
void _COLUMNDATA::ReleaseColumnData( )
|
|
{
|
|
CDataMap Map;
|
|
if(pbData != NULL)
|
|
{
|
|
Map.FreeData(dwType,pbData);
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
// Get pointer to a particular columndata
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
PCOLUMNDATA tagRowBuff::GetColumnData(int iCol)
|
|
{
|
|
return (pdData + iCol);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
// Set the rowdata pointer
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
HRESULT tagRowBuff::SetRowData(PCOLUMNDATA pColData)
|
|
{
|
|
pdData = pColData;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Allocates a contiguous block of the required number of slots.
|
|
//
|
|
// Returns one of the following values:
|
|
// S_OK slot allocate succeeded
|
|
// E_OUTOFMEMORY slot allocation failed because of memory allocation problem
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
HRESULT GetNextSlots ( PLSTSLOT plstslot, //IN slot list
|
|
HSLOT cslot, //IN needed block size (in slots)
|
|
HSLOT* pislot //IN handle of the first slot in the returned block
|
|
)
|
|
{
|
|
HSLOT islot, dslot;
|
|
PSLOT pslot, pslotTmp;
|
|
LONG_PTR cbCommit;
|
|
HRESULT hr = S_OK;
|
|
|
|
if (plstslot->islotRov)
|
|
{
|
|
plstslot->islotRov = ((PSLOT) & plstslot->rgslot[(plstslot->islotRov * plstslot->cbSlot)-sizeof(SLOT)])->islotNext;
|
|
}
|
|
else
|
|
{
|
|
plstslot->islotRov = plstslot->islotFirst;
|
|
}
|
|
|
|
islot = plstslot->islotRov;
|
|
while (islot)
|
|
{
|
|
if (((PSLOT) & plstslot->rgslot[(islot *plstslot->cbSlot)-sizeof(SLOT)])->cslot >= cslot)
|
|
{
|
|
break;
|
|
}
|
|
islot = ((PSLOT) & plstslot->rgslot[(islot *plstslot->cbSlot)-sizeof(SLOT)])->islotNext;
|
|
}
|
|
if (islot == 0)
|
|
{
|
|
islot = plstslot->islotFirst;
|
|
while (islot != plstslot->islotRov)
|
|
{
|
|
if (((PSLOT) & plstslot->rgslot[(islot *plstslot->cbSlot)-sizeof(SLOT)])->cslot >= cslot)
|
|
{
|
|
break;
|
|
}
|
|
islot = ((PSLOT) & plstslot->rgslot[(islot *plstslot->cbSlot)-sizeof(SLOT)])->islotNext;
|
|
}
|
|
if (islot == plstslot->islotRov)
|
|
islot = 0;
|
|
}
|
|
|
|
if (islot == 0)
|
|
{
|
|
cbCommit = ((cslot *plstslot->cbSlot) / plstslot->cbPage + 1) *plstslot->cbPage;
|
|
if ((plstslot->cbCommitCurrent + cbCommit) > plstslot->cbCommitMax
|
|
|| VirtualAlloc((VOID *) ((BYTE *) plstslot + plstslot->cbCommitCurrent),
|
|
cbCommit,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE ) == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY ;
|
|
}
|
|
else
|
|
{
|
|
islot = (HSLOT) ((plstslot->cbCommitCurrent + plstslot->cbExtra) / plstslot->cbSlot);
|
|
dslot = ((cbCommit + plstslot->cbslotLeftOver) / plstslot->cbSlot);
|
|
if ((plstslot->pbitsSlot)->IsSlotSet( islot - 1 ) != NOERROR)
|
|
{
|
|
if ((plstslot->pbitsSlot)->FindSet( islot - 1, plstslot->islotMin, &islot ) == NOERROR)
|
|
{
|
|
islot++;
|
|
}
|
|
else
|
|
{
|
|
islot = plstslot->islotMin;
|
|
}
|
|
pslot = (PSLOT) & plstslot->rgslot[(islot *plstslot->cbSlot)-sizeof(SLOT)];
|
|
pslot->cslot += dslot;
|
|
DecoupleSlot( plstslot, islot, pslot );
|
|
}
|
|
else
|
|
{
|
|
// pslot = (PSLOT) ((BYTE *) plstslot + plstslot->cbCommitCurrent - plstslot->cbslotLeftOver);
|
|
pslot = (PSLOT) & plstslot->rgslot[(islot *plstslot->cbSlot)-sizeof(SLOT)];
|
|
pslot->cslot = dslot;
|
|
}
|
|
|
|
pslot->islotNext = plstslot->islotFirst;
|
|
pslot->islotPrev = 0;
|
|
|
|
plstslot->islotMax += dslot;
|
|
plstslot->islotFirst = islot;
|
|
plstslot->cbslotLeftOver = (cbCommit + plstslot->cbslotLeftOver) % plstslot->cbSlot;
|
|
plstslot->cbCommitCurrent += cbCommit;
|
|
|
|
if (pslot->islotNext)
|
|
{
|
|
((PSLOT) & plstslot->rgslot[(pslot->islotNext *plstslot->cbSlot)-sizeof(SLOT)])->islotPrev = islot;
|
|
}
|
|
islot = plstslot->islotFirst;
|
|
}
|
|
}
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
pslot = (PSLOT) & plstslot->rgslot[(islot *plstslot->cbSlot)-sizeof(SLOT)];
|
|
DecoupleSlot( plstslot, islot, pslot );
|
|
if (pslot->cslot > cslot)
|
|
{
|
|
pslotTmp = (PSLOT) & plstslot->rgslot[ ((islot + cslot) *plstslot->cbSlot)-sizeof(SLOT)];
|
|
pslotTmp->cslot = pslot->cslot - cslot;
|
|
AddSlotToList( plstslot, islot + cslot, pslotTmp );
|
|
}
|
|
|
|
if (SUCCEEDED( hr = (plstslot->pbitsSlot)->SetSlots( islot, islot + cslot - 1 )))
|
|
{
|
|
if (pislot)
|
|
{
|
|
*pislot = islot;
|
|
}
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Decouples a slot from the list of free slots
|
|
//
|
|
// NONE
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID DecoupleSlot ( PLSTSLOT plstslot, //IN slot list
|
|
HSLOT islot, //IN slot handle to decouple
|
|
PSLOT pslot //IN pointer to the slot header
|
|
)
|
|
{
|
|
PSLOT slotTemp = NULL;
|
|
if (pslot->islotNext)
|
|
{
|
|
slotTemp = (PSLOT) & plstslot->rgslot[(pslot->islotNext *plstslot->cbSlot)-sizeof(SLOT)];
|
|
slotTemp->islotNext = pslot->islotPrev;
|
|
((PSLOT) & plstslot->rgslot[(pslot->islotNext *plstslot->cbSlot)-sizeof(SLOT)])->islotPrev = pslot->islotPrev;
|
|
}
|
|
if (pslot->islotPrev)
|
|
{
|
|
((PSLOT) & plstslot->rgslot[(pslot->islotPrev *plstslot->cbSlot)-sizeof(SLOT)])->islotNext = pslot->islotNext;
|
|
}
|
|
else
|
|
{
|
|
plstslot->islotFirst = pslot->islotNext;
|
|
}
|
|
if (islot == plstslot->islotRov)
|
|
{
|
|
plstslot->islotRov = pslot->islotNext;
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Adds a slot to the list of free slots
|
|
//
|
|
// NONE
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
VOID AddSlotToList ( PLSTSLOT plstslot, //IN slot list
|
|
HSLOT islot, //IN slot handle
|
|
PSLOT pslot //IN pointer to the slot header
|
|
)
|
|
{
|
|
pslot->islotPrev = 0;
|
|
pslot->islotNext = plstslot->islotFirst;
|
|
plstslot->islotFirst = islot;
|
|
if (pslot->islotNext)
|
|
{
|
|
((PSLOT) & plstslot->rgslot[(pslot->islotNext *plstslot->cbSlot)-sizeof(SLOT)])->islotPrev = islot;
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// ReleaseSlots
|
|
//
|
|
// Releases a contiguous block of slots.
|
|
//
|
|
// Returns one of the following values:
|
|
// S_OK | method succeeded
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
HRESULT ReleaseSlots ( PLSTSLOT plstslot, //IN slot list
|
|
HSLOT islot, //IN handle of first slot to release
|
|
ULONG_PTR cslot //IN count of slots to release
|
|
)
|
|
{
|
|
PSLOT pslot, pslotTmp;
|
|
|
|
(plstslot->pbitsSlot)->ResetSlots( islot, islot + cslot - 1 );
|
|
pslot = (PSLOT) & plstslot->rgslot[(islot * plstslot->cbSlot)-sizeof(SLOT)];
|
|
pslot->cslot = cslot;
|
|
|
|
if (islot > plstslot->islotMin && (plstslot->pbitsSlot)->IsSlotSet( islot - 1 ) != NOERROR)
|
|
{
|
|
if ((plstslot->pbitsSlot)->FindSet( islot - 1, plstslot->islotMin, &islot ) == NOERROR)
|
|
{
|
|
islot++;
|
|
}
|
|
else
|
|
{
|
|
islot = plstslot->islotMin;
|
|
}
|
|
pslot = (PSLOT) & plstslot->rgslot[(islot * plstslot->cbSlot)-sizeof(SLOT)];
|
|
pslot->cslot += cslot;
|
|
DecoupleSlot( plstslot, islot, pslot );
|
|
}
|
|
else
|
|
if ((islot + cslot) <= (ULONG_PTR)plstslot->islotMax && (plstslot->pbitsSlot)->IsSlotSet( islot + cslot ) != NOERROR)
|
|
{
|
|
pslotTmp = (PSLOT) & plstslot->rgslot[ ((islot + cslot) *plstslot->cbSlot)-sizeof(SLOT)];
|
|
pslot->cslot += pslotTmp->cslot;
|
|
DecoupleSlot( plstslot, (islot + cslot), pslotTmp );
|
|
}
|
|
|
|
AddSlotToList( plstslot, islot, pslot );
|
|
return S_OK ;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Initializes the Slot List object
|
|
//
|
|
// Did the initialization succeed
|
|
// S_OK | method succeeded
|
|
// E_OUTOFMEMORY | failed, out of memory
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
HRESULT InitializeSlotList( ULONG_PTR cslotMax, //IN max number of slots
|
|
ULONG_PTR cbSlot, //IN slot size (row buffer size)
|
|
ULONG_PTR cbPage, //IN page size
|
|
LPBITARRAY pbits, //IN
|
|
PLSTSLOT* pplstslot, //OUT pointer to slot list
|
|
BYTE** prgslot //OUT
|
|
)
|
|
{
|
|
LONG_PTR cbReserve;
|
|
BYTE * pbAlloc;
|
|
ULONG_PTR cbCommitFirst;
|
|
PLSTSLOT plstslot;
|
|
ULONG_PTR cslot, islotFirst;
|
|
PSLOT pslot;
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
if (cbPage == 0)
|
|
{
|
|
SYSTEM_INFO sysinfo;
|
|
|
|
GetSystemInfo( &sysinfo );
|
|
cbPage = sysinfo.dwPageSize;
|
|
}
|
|
|
|
// Add in the LSTSLOT and SLOT
|
|
cbSlot = cbSlot + (sizeof( LSTSLOT ) + sizeof( SLOT ));
|
|
cbReserve = ((cslotMax *(cbSlot + (sizeof( LSTSLOT ) + sizeof( SLOT )))) / cbPage + 1) *cbPage;
|
|
|
|
pbAlloc = (BYTE *) VirtualAlloc( NULL, cbReserve, MEM_RESERVE, PAGE_READWRITE );
|
|
if (pbAlloc == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY ;
|
|
}
|
|
else
|
|
{
|
|
|
|
cbCommitFirst = ((sizeof( LSTSLOT ) + sizeof( SLOT )) / cbPage + 1) * cbPage;
|
|
plstslot = (PLSTSLOT) VirtualAlloc( pbAlloc, cbCommitFirst, MEM_COMMIT, PAGE_READWRITE );
|
|
if (plstslot == NULL)
|
|
{
|
|
VirtualFree((VOID *) pbAlloc, 0, MEM_RELEASE );
|
|
hr = E_OUTOFMEMORY ;
|
|
}
|
|
else
|
|
{
|
|
|
|
plstslot->cbSlot = cbSlot;
|
|
plstslot->cbPage = cbPage;
|
|
plstslot->cbCommitCurrent = cbCommitFirst;
|
|
plstslot->cbCommitMax = cbReserve;
|
|
plstslot->pbitsSlot = pbits;
|
|
|
|
|
|
if (cbSlot <= 2*(sizeof( LSTSLOT ) + sizeof( SLOT )))
|
|
{
|
|
islotFirst = (sizeof( LSTSLOT ) + sizeof( SLOT )) / cbSlot + (((sizeof( LSTSLOT ) + sizeof( SLOT )) % cbSlot) ? 1 : 0);
|
|
plstslot->cbExtra = 0;
|
|
cslot = (ULONG_PTR) ((cbCommitFirst / cbSlot) - islotFirst);
|
|
plstslot->cbslotLeftOver = cbCommitFirst - cbSlot * (cslot + islotFirst);
|
|
}
|
|
else
|
|
{
|
|
islotFirst = 1;
|
|
plstslot->cbExtra = cbSlot - (sizeof( LSTSLOT ) + sizeof( SLOT ));
|
|
cslot = (cbCommitFirst - (sizeof( LSTSLOT ) + sizeof( SLOT ))) / cbSlot;
|
|
plstslot->cbslotLeftOver = cbCommitFirst - (sizeof( LSTSLOT ) + sizeof( SLOT )) - cslot*cbSlot;
|
|
}
|
|
plstslot->rgslot = ((BYTE *) plstslot - plstslot->cbExtra);
|
|
if (cslot)
|
|
{
|
|
plstslot->islotFirst = islotFirst;
|
|
pslot = (PSLOT) & plstslot->rgslot[(islotFirst *plstslot->cbSlot)-sizeof(SLOT)];
|
|
pslot->cslot = cslot;
|
|
pslot->islotNext = 0;
|
|
pslot->islotPrev = 0;
|
|
}
|
|
else
|
|
{
|
|
plstslot->islotFirst = 0;
|
|
}
|
|
plstslot->islotMin = islotFirst;
|
|
plstslot->islotMax = islotFirst + cslot - 1;
|
|
plstslot->islotRov = plstslot->islotFirst;
|
|
|
|
*pplstslot = plstslot;
|
|
*prgslot = plstslot->rgslot;
|
|
}
|
|
}
|
|
|
|
return hr ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Restore slot list to newly-initiated state
|
|
//
|
|
//
|
|
// S_OK | method succeeded
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
HRESULT ResetSlotList ( PLSTSLOT plstslot )
|
|
{
|
|
ULONG_PTR cslot;
|
|
PSLOT pslot;
|
|
|
|
cslot = (plstslot->islotMax >= plstslot->islotMin) ? (plstslot->islotMax - plstslot->islotMin + 1) : 0;
|
|
if (cslot)
|
|
{
|
|
plstslot->islotFirst = plstslot->islotMin;
|
|
pslot = (PSLOT) & plstslot->rgslot[(plstslot->islotFirst *plstslot->cbSlot)-sizeof(SLOT)];
|
|
pslot->cslot = cslot;
|
|
pslot->islotNext = 0;
|
|
pslot->islotPrev = 0;
|
|
}
|
|
else
|
|
{
|
|
plstslot->islotFirst = 0;
|
|
}
|
|
|
|
plstslot->islotRov = plstslot->islotFirst;
|
|
return S_OK ;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Free slot list's memory
|
|
//
|
|
//
|
|
// S_OK | method succeeded
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
HRESULT ReleaseSlotList ( PLSTSLOT plstslot )
|
|
{
|
|
if (plstslot != NULL)
|
|
{
|
|
if (plstslot->cbCommitCurrent)
|
|
{
|
|
VirtualFree((VOID *) plstslot, plstslot->cbCommitCurrent, MEM_DECOMMIT );
|
|
}
|
|
|
|
VirtualFree((VOID *) plstslot, 0, MEM_RELEASE );
|
|
}
|
|
return S_OK ;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// gets the buffer address for the slot
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
ROWBUFF* GetRowBuffer(PLSTSLOT plstslot , HSLOT islot)
|
|
{
|
|
BYTE *pTemp = & (plstslot->rgslot[(islot * plstslot->cbSlot)]);
|
|
ROWBUFF * pBuff = (ROWBUFF *)&(plstslot->rgslot[(islot * plstslot->cbSlot)]);
|
|
return pBuff;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
//////////// CHashTbl Implementation /////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
// CHashTbl::CHashTbl
|
|
//
|
|
// @mfunc CHashTbl constructor.
|
|
//
|
|
// @rdesc NONE
|
|
//-----------------------------------------------------------------------------------
|
|
|
|
CHashTbl::CHashTbl()
|
|
{
|
|
m_rgwHash = NULL;
|
|
m_ulTableSize = 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
// CHashTbl::~CHashTbl
|
|
//
|
|
// @mfunc CHashTbl destructor.
|
|
//
|
|
// @rdesc NONE
|
|
//-----------------------------------------------------------------------------------
|
|
CHashTbl::~CHashTbl()
|
|
{
|
|
if (m_rgwHash)
|
|
g_pIMalloc->Free(m_rgwHash);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
// CHashTbl::FInit
|
|
//
|
|
// Initialize the Hashtable object.
|
|
//
|
|
// Did the Initialization Succeed
|
|
// TRUE Initialization succeeded
|
|
// FALSE Initializtion failed
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CHashTbl::FInit(PLSTSLOT pLstSlot)
|
|
{
|
|
|
|
BOOL bRet = TRUE;
|
|
|
|
// Initialize the hashtable size
|
|
m_ulTableSize = HASHTBLSIZE;
|
|
|
|
// Allocate the table.
|
|
m_rgwHash = (USHORT*)g_pIMalloc->Alloc(m_ulTableSize*sizeof(USHORT));
|
|
if (m_rgwHash == NULL)
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
{
|
|
memset(m_rgwHash, 0x00, m_ulTableSize*sizeof(USHORT)); // Initialize.
|
|
m_pLstSlot = pLstSlot;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
// CHashTbl::InsertFindBmk
|
|
//
|
|
// Either only check if a given bookmark is already in the hashtable
|
|
// (fFindOnly = TRUE), or check, and if it is not there, insert.
|
|
//
|
|
// Returns one of the following values:
|
|
// S_OK Bookmark found in the hashtable,
|
|
// S_FALSE Bookmark not found, if fFindOnly = FALSE, the new row
|
|
// with this bookmark was inserted in the table.
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CHashTbl::InsertFindBmk
|
|
(
|
|
BOOL fFindOnly, //@parm IN | FindOnly or Find/Insert
|
|
HSLOT iSlot, //@parm IN | handle of the rowbuffer to be inserted
|
|
ULONG_PTR cbBmk, //@parm IN | bookmark length
|
|
BYTE *pbBmk, //@parm IN | bookmark pointer
|
|
ULONG_PTR *pirowSlotFound //@parm OUT | if bookmark found returns handle of the
|
|
// row that contains the bookmark
|
|
)
|
|
{
|
|
//NTRaid:111766
|
|
// 06/07/00
|
|
DBHASHVALUE BmkHash = 0;
|
|
HROW iSlotCurr = 0;
|
|
PROWBUFF prowbuffCur = NULL;
|
|
HRESULT hr = S_FALSE;
|
|
|
|
|
|
assert(cbBmk == BOOKMARKSIZE && pbBmk);
|
|
assert(pirowSlotFound);
|
|
|
|
// Hash the bookmark. The hash value indexes the hashtable element which, if
|
|
// not empty, will contain the handle to the beginning of the list of rows whose
|
|
// bookmarks hash to the same value.
|
|
HashBmk(cbBmk, pbBmk, &BmkHash);
|
|
|
|
assert(BmkHash <= m_ulTableSize);
|
|
|
|
iSlotCurr = m_rgwHash[BmkHash];
|
|
// If the entry is non-zero, search the corresponding list for this bookmark.
|
|
if (iSlotCurr)
|
|
{
|
|
prowbuffCur = GetRowBuffer(m_pLstSlot,iSlotCurr);
|
|
iSlotCurr = 0;
|
|
// Walk the overflow list looking for bookmark match.
|
|
while (prowbuffCur)
|
|
{
|
|
assert(prowbuffCur->dwBmk && "Error attempting to compare bookmark on invalid row");
|
|
|
|
// Compare the bookmarks
|
|
if (cbBmk == prowbuffCur->cbBmk && cbBmk == BOOKMARKSIZE &&
|
|
memcmp(&(prowbuffCur->dwBmk), pbBmk , BOOKMARKSIZE) == 0)
|
|
{
|
|
iSlotCurr = prowbuffCur->ulSlot;
|
|
break;
|
|
}
|
|
prowbuffCur = prowbuffCur->prowbuffNext;
|
|
}
|
|
}
|
|
|
|
// No insertion in the hashtable is needed or necessary.
|
|
if (fFindOnly || iSlotCurr)
|
|
{
|
|
*pirowSlotFound = iSlotCurr; // Return the index of the rowbuffer that has
|
|
// this bookmark, or 0 if none.
|
|
hr = iSlotCurr ? S_OK : S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
|
|
// Get the pointer to the row to be inserted.
|
|
prowbuffCur = GetRowBuffer(m_pLstSlot,iSlot);
|
|
|
|
// Initialize the new node for the list.
|
|
if (m_rgwHash[BmkHash])
|
|
{
|
|
prowbuffCur->prowbuffNext = GetRowBuffer(m_pLstSlot,(ULONG)MAKELONG(m_rgwHash[BmkHash], 0));
|
|
}
|
|
else
|
|
{
|
|
prowbuffCur->prowbuffNext = NULL;
|
|
}
|
|
|
|
prowbuffCur->wBmkHash = (USHORT)BmkHash;
|
|
prowbuffCur->ulSlot = iSlot;
|
|
|
|
// Always insert a new node at the beginning of the list.
|
|
m_rgwHash[BmkHash] = LOWORD(iSlot);
|
|
|
|
*pirowSlotFound = iSlot;
|
|
}
|
|
|
|
// S_FALSE signifies that originally there was no row with this bookmark
|
|
// in the hashtable.
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
// CRowset::HashBmk
|
|
//
|
|
// Hashes a fixed-size bookmark for a table of given size.
|
|
//
|
|
// Returns one of the following values:
|
|
// S_OK Hashing succeeded,
|
|
// E_INVALIDARG Hashing failed because the bookmark was invalid
|
|
// or the pointer to bookmark was NULL.
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CHashTbl::HashBmk
|
|
(
|
|
DBBKMARK cbBmk,
|
|
const BYTE *pbBmk,
|
|
DBHASHVALUE *pdwHashedValue)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (cbBmk != BOOKMARKSIZE || pbBmk == NULL)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
assert(pdwHashedValue);
|
|
|
|
*pdwHashedValue = (*(UNALIGNED ULONG*)pbBmk) % m_ulTableSize;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
// CHashTbl::DeleteBmk
|
|
//
|
|
// Delete a bookmark corresponding to a given row from the hashtable.
|
|
//
|
|
// Returns one of the following values:
|
|
// S_OK Bookmark was found and deleted from the hashtable,
|
|
// S_FALSE Bookmark was not found in the hashtable.
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CHashTbl::DeleteBmk
|
|
(
|
|
HSLOT ulSlot //@parm IN | handle of the rowbuffer with bookmark to be deleted.
|
|
)
|
|
{
|
|
HSLOT iSlotCur;
|
|
USHORT wBmkHash;
|
|
HRESULT hr = S_OK;
|
|
PROWBUFF * pprowbuffCur, prowbuffFirst;
|
|
|
|
|
|
wBmkHash = GetRowBuffer(m_pLstSlot,ulSlot)->wBmkHash;
|
|
|
|
iSlotCur = MAKELONG(m_rgwHash[wBmkHash], 0);
|
|
//==============================================================
|
|
// If there is a non-zero entry search the corresponding list.
|
|
//==============================================================
|
|
if (ulSlot)
|
|
{
|
|
pprowbuffCur = &prowbuffFirst;
|
|
prowbuffFirst = GetRowBuffer(m_pLstSlot,iSlotCur);
|
|
while (*pprowbuffCur)
|
|
{
|
|
//===========================================================
|
|
// To delete a row under a given index just compare indices,
|
|
// no need to look at bookmarks.
|
|
//===========================================================
|
|
if (ulSlot == (*pprowbuffCur)->ulSlot)
|
|
{
|
|
break;
|
|
}
|
|
pprowbuffCur = &(*pprowbuffCur)->prowbuffNext;
|
|
}
|
|
|
|
if (*pprowbuffCur == NULL)
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
if(hr == S_OK)
|
|
{
|
|
// Remove the row from the list.
|
|
if (pprowbuffCur == &prowbuffFirst)
|
|
{
|
|
m_rgwHash[wBmkHash] = (USHORT)((prowbuffFirst->prowbuffNext) ? (prowbuffFirst->prowbuffNext)->ulSlot : 0);
|
|
}
|
|
else
|
|
{
|
|
*pprowbuffCur = (*pprowbuffCur)->prowbuffNext;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|