windows-nt/Source/XPSP1/NT/admin/wmi/wbem/adapters/oledb/rowfetchobj.cpp
2020-09-26 16:20:57 +08:00

645 lines
21 KiB
C++

///////////////////////////////////////////////////////////////////////////////////
//
// Microsoft WMIOLE DB Provider
// (C) Copyright 1999 Microsoft Corporation. All Rights Reserved.
//
// CRowFetchObj class implementation
//
//
///////////////////////////////////////////////////////////////////////////////////
#include "headers.h"
#include "WmiOleDBMap.h"
/////////////////////////////////////////////////////////////////////////////////////
////CRowFetchObj class Implementation
/////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
// Function which fetches data and puts it into the given buffer
// NTRaid:111834
// 06/07/00
///////////////////////////////////////////////////////////////////////////////////////////
HRESULT CRowFetchObj::FetchData(CRowset * pRowset,
HROW hRow, //IN Row Handle
HACCESSOR hAccessor, //IN Accessor to use
void *pData )
{
// NTRaid:111834
// 06/13/00
PACCESSOR pAccessor = NULL;
DBORDINAL icol = 0;
DBORDINAL ibind = 0;
ROWBUFF *pRowBuff = NULL;
COLUMNDATA *pColumnData = NULL;
DBBINDING *pBinding = NULL;
DBROWCOUNT cBindings = NULL;
ULONG ulErrorCount = 0;
DBTYPE dwSrcType = 0;
DBTYPE dwDstType = 0;
void *pSrc = NULL;
void *pDst = NULL;
DBLENGTH ulSrcLength = 0;
DBLENGTH *pulDstLength = NULL;
DBLENGTH ulDstMaxLength = 0;
DBSTATUS dwSrcStatus = 0;
DBSTATUS *pdwDstStatus = NULL;
DWORD dwPart = 0;
HRESULT hr = S_OK;
HSLOT hSlot = 0;
BOOL bUseDataConvert = TRUE;
CWbemClassWrapper * pInst = NULL;
CDataMap dataMap;
//========================================================================================
// Coerce data for row 'hRow', according to hAccessor. Put in location 'pData'.
// Offsets and types are in hAccessor's bindings.
//
// Return S_OK if all lossless conversions,
// return DB_S_ERRORSOCCURED if lossy conversion (truncation, rounding, etc.)
// Return E_FAIL, etc., if horrible errors.
// GetItemOfExtBuffer is basically operator[].
// It takes an index (or handle) (referenced from 1...n),
// and a ptr for where to write the data.
//
// It holds ptrs to a variable-length ACCESSOR struct.
// So we get the ACCESSOR ptr for the client's accessor handle.
//========================================================================================
assert( pRowset->m_pIAccessor->GetAccessorPtr());
hr = pRowset->m_pIAccessor->GetAccessorPtr()->GetItemOfExtBuffer( hAccessor, &pAccessor );
if (FAILED( hr ) || pAccessor == NULL)
{
hr = DB_E_BADACCESSORHANDLE;
}
else
{
assert( pAccessor );
cBindings = pAccessor->cBindings;
pBinding = pAccessor->rgBindings;
//========================================================================================
// Ensure a place to put data, unless the accessor is the null accessor then
// a NULL pData is okay.
//========================================================================================
if ( pData == NULL && cBindings != 0 )
{
hr = E_INVALIDARG ;
}
else
//========================================================================================
// IsSlotSet returns S_OK if row is marked.
// S_FALSE if row is not marked.
// The "mark" means that there is data present in the row.
// Rows are [1...n], slot marks are [0...n-1].
//========================================================================================
if (pRowset->IsSlotSet(hRow ) != S_OK)
{
hr = DB_E_BADROWHANDLE;
}
else
//===================================================================
// if data is not already fetched to the memory ( which is done
// if other updatedelete is false)
//===================================================================
if( (pRowset->m_ulProps & OTHERUPDATEDELETE) && (pRowset->m_ulLastFetchedRow != hRow))
{
if(SUCCEEDED (hr = pRowset->GetDataToLocalBuffer(hRow)))
{
pRowset->m_ulLastFetchedRow = hRow;
}
}
if(SUCCEEDED(hr))
{
//========================================================================================
// Internal error for a 0 reference count on this row,
// since we depend on the slot-set stuff.
//========================================================================================
pRowBuff = pRowset->GetRowBuff( (ULONG) hRow, TRUE );
assert( pRowBuff->ulRefCount );
//========================================================================================
// Check for the Deleted Row
//========================================================================================
ulErrorCount = 0;
for (ibind = 0; ibind < (DBORDINAL)cBindings; ibind++) {
bUseDataConvert = TRUE;
icol = pBinding[ibind].iOrdinal;
// pColumnData = pRowBuff->GetColumnData(icol);
//========================================================================================
// If bookmark is not requested by setting the DBPROP_BOOKMARK property
// then skip getting the bookmark
//========================================================================================
if(!(pRowset->m_ulProps & BOOKMARKPROP) && icol == 0)
{
continue;
}
else
//========================================================================================
// if it is a bookmark column get the bookmark column from the ROWBUFF Structure
//========================================================================================
if(icol == 0)
{
dwSrcType = DBTYPE_I4;
pSrc = &pRowBuff->dwBmk;
ulSrcLength = pRowBuff->cbBmk;
dwSrcStatus = DBSTATUS_S_OK;
}
else
{
pColumnData = (COLUMNDATA *) ((BYTE *) pRowBuff + pRowset->m_Columns.GetDataOffset(icol));
dwSrcType = (DBTYPE)pColumnData->dwType ; //pRowset->m_Columns.ColumnType(icol);
//===================================================================
// FIXXX More work is to be done on this
//===================================================================
if( dwSrcType == DBTYPE_BSTR )
{
pSrc = &(pColumnData->pbData);
}
else
{
pSrc = (pColumnData->pbData);
}
ulSrcLength = pColumnData->dwLength;
dwSrcStatus = pColumnData->dwStatus;
if(dwSrcType == DBTYPE_HCHAPTER)
{
dwSrcType = DBTYPE_UI4;
}
}
ulDstMaxLength = pBinding[ibind].cbMaxLen;
dwDstType = pBinding[ibind].wType;
dwPart = pBinding[ibind].dwPart;
pDst = dwPart & DBPART_VALUE ? ((BYTE*) pData + pBinding[ibind].obValue) : NULL;
pulDstLength = dwPart & DBPART_LENGTH ? (DBLENGTH *) ((BYTE*) pData + pBinding[ibind].obLength) : NULL;
pdwDstStatus = dwPart & DBPART_STATUS ? (DBSTATUS *) ((BYTE*) pData + pBinding[ibind].obStatus) : NULL;
//==========================================================
// if the column is of type chapter then consider that
// as a of type long as HCHAPTER is a ULONG value
//==========================================================
if(dwDstType == DBTYPE_HCHAPTER)
{
dwDstType = DBTYPE_UI4;
}
if((dwSrcType & DBTYPE_ARRAY) && (dwDstType & DBTYPE_ARRAY))
{
bUseDataConvert = FALSE;
}
if( dwSrcType != VT_NULL && dwSrcType != VT_EMPTY && bUseDataConvert == TRUE && pSrc != NULL)
{
BSTR strData;
if( dwDstType == DBTYPE_BSTR && pDst == NULL)
{
void **pTemp = &pDst;
*pTemp = (void *)&strData;
}
hr = g_pIDataConvert->DataConvert(
dwSrcType,
dwDstType,
ulSrcLength,
pulDstLength,
pSrc,
pDst,
ulDstMaxLength,
dwSrcStatus,
pdwDstStatus,
pBinding[ibind].bPrecision, // bPrecision for conversion to DBNUMERIC
pBinding[ibind].bScale, // bScale for conversion to DBNUMERIC
DBDATACONVERT_DEFAULT);
if(!(dwPart & DBPART_VALUE) && pulDstLength != NULL)
{
hr =g_pIDataConvert->GetConversionSize(dwSrcType,dwDstType,&ulSrcLength,pulDstLength,pSrc);
}
if(!(dwPart & DBPART_VALUE) && dwDstType == DBTYPE_BSTR )
{
if(pulDstLength != NULL)
{
*pulDstLength = SysStringLen(strData);
}
SysFreeString(strData);
}
if(hr == DB_E_UNSUPPORTEDCONVERSION && pdwDstStatus != NULL)
{
*pdwDstStatus = DBSTATUS_E_CANTCONVERTVALUE;
}
}
else
if(bUseDataConvert == FALSE && pSrc != NULL )
{
if(pDst != NULL)
{
//========================================================================================
// Call this function to get the array in the destination address
//========================================================================================
hr = dataMap.ConvertAndCopyArray((SAFEARRAY *)pSrc,(SAFEARRAY **)pDst, dwSrcType,dwDstType,pdwDstStatus);
}
if(pulDstLength != NULL)
{
*pulDstLength = sizeof(SAFEARRAY);
}
if( pdwDstStatus != NULL && *pdwDstStatus == DBSTATUS_E_CANTCONVERTVALUE && pulDstLength != NULL)
{
*pulDstLength = 0;
}
}
else
{
if(pulDstLength)
{
*pulDstLength = 0;
}
if(pdwDstStatus)
{
*pdwDstStatus = DBSTATUS_S_ISNULL;
}
}
if (hr != S_OK )
{
ulErrorCount++; // can't coerce
}
} // for loop
} // if succeeded(hr)
} // else for check for bad accessor
//===================================================================
// We report any lossy conversions with a special status.
// Note that DB_S_ERRORSOCCURED is a success, rather than failure.
//===================================================================
if ( SUCCEEDED(hr) )
{
hr = ( ulErrorCount ? DB_S_ERRORSOCCURRED : S_OK );
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Function to clear all the allocated buffer if any error occurs while getting data
///////////////////////////////////////////////////////////////////////////////////////////
void CRowFetchObj::ClearRowBuffer(void *pData,
DBBINDING *pBinding,
int nCurCol)
{
ULONG *pulDstLength;
DWORD *pdwDstStatus;
CDataMap map;
void *pDst;
DWORD dwPart;
//========================================================================================
// Check for the Deleted Row
//========================================================================================
for (int ibind = 0; ibind < nCurCol; ibind++)
{
dwPart = pBinding[ibind].dwPart;
pDst = dwPart & DBPART_VALUE ? ((BYTE*) pData + pBinding[ibind].obValue) : NULL;
pulDstLength = dwPart & DBPART_LENGTH ? (ULONG *) ((BYTE*) pData + pBinding[ibind].obLength) : NULL;
pdwDstStatus = dwPart & DBPART_STATUS ? (ULONG *) ((BYTE*) pData + pBinding[ibind].obStatus) : NULL;
if(pDst)
{
map.ClearData(pBinding[ibind].wType,(BYTE *)pDst);
}
if(pulDstLength)
{
*pulDstLength = 0;
}
if(pdwDstStatus)
{
*pdwDstStatus = 0;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Function which get the position of the first row to be fetched
///////////////////////////////////////////////////////////////////////////////////////////
LONG_PTR CRowFetchObj::GetFirstFetchPos(CRowset *pRowset,DBCOUNTITEM cRows,DBROWOFFSET lOffset)
{
FETCHDIRECTION lFetchDir;
LONG_PTR lFirstPos = -1;
lFetchDir = (LONG_PTR)cRows < 0 ? FETCHDIRBACKWARD : FETCHDIRFORWARD;
if( cRows != 0)
{
lFirstPos = pRowset->m_lLastFetchPos + lOffset;
if((pRowset->m_FetchDir != FETCHDIRNONE) && pRowset->m_FetchDir != lFetchDir)
{
}
else
{
lFirstPos = (LONG_PTR)cRows < 0 ? lFirstPos - 1 : lFirstPos + 1;
}
}
if(lFirstPos <= 0)
{
lFirstPos = -1;
}
return lFirstPos;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Function which get the position of the first row to be fetched
// NTRaid:111770
// 06/07/00
///////////////////////////////////////////////////////////////////////////////////////////
HRESULT CRowFetchObj::FetchRowsByBookMark(CRowset * pRowset,
HCHAPTER hChapter, // IN The Chapter handle.
DBROWCOUNT cRows, // IN Number of rows to fetch
const DBBKMARK rgcbBookmarks[], //@parm IN | an array of bookmark sizes
const BYTE* rgpBookmarks[], //@parm IN | an array of pointers to bookmarks
HROW rghRows[], // OUT Array of Hrows obtained
DBROWSTATUS rgRowStatus[]) // OUT status of rows
{
DBCOUNTITEM ibmk, cErrors, cRowsObtained;
PROWBUFF prowbuff;
HROW hrow, hrowFound;
HRESULT hr;
BYTE* pbBmk;
DBBKMARK cbBmk;
DBROWSTATUS dbrowstatus;
ULONG_PTR ulLastFetchPos;
FETCHDIRECTION lFetchDir;
DBROWOFFSET lOffset = 0;
HROW * phRow;
ulLastFetchPos = pRowset->m_lLastFetchPos;
lFetchDir = pRowset->m_FetchDir;
if(pRowset->m_FetchDir == FETCHDIRNONE)
{
pRowset->m_FetchDir = FETCHDIRFORWARD;
}
//========================================================================================
// Now, loop thru all supplied bookmarks.
//========================================================================================
for (ibmk =0, cErrors =0; ibmk < (DBCOUNTITEM)cRows; ibmk++)
{
pbBmk = (BYTE*)&rgpBookmarks[ibmk];
cbBmk = pbBmk? rgcbBookmarks[ibmk] : 0;
//========================================================================================
// Must be a valid bookmark
//========================================================================================
if (cbBmk != BOOKMARKSIZE)
{
dbrowstatus = DBROWSTATUS_E_INVALID;
hrow = DB_NULL_HROW;
}
//========================================================================================
// We might already have this bookmark in our hashtable.
//========================================================================================
else if (pRowset->m_pHashTblBkmark->InsertFindBmk(TRUE, 0,
cbBmk, pbBmk, &hrow) == S_OK)
{
//========================================================================================
// Row handle for this Bookmark was already in memory,
// so return the row handle that was found.
//========================================================================================
prowbuff = pRowset->GetRowBuffFromSlot(hrow);
if (pRowset->GetRowStatus(hrow) & DBROWSTATUS_E_DELETED)
{
dbrowstatus = DBROWSTATUS_E_INVALID;
hrow = DB_NULL_HROW;
}
else
{
dbrowstatus = DBROWSTATUS_S_OK;
prowbuff->ulRefCount++;
}
}
else
//==========================================================================================
// if bookmark not alread present then fetch the row and put the bookmark in hash table
//==========================================================================================
{
lOffset = *((ULONG *)pbBmk) - pRowset->m_lLastFetchPos;
lOffset = (pRowset->m_FetchDir == FETCHDIRFORWARD) ? --lOffset : ++lOffset;
cRowsObtained = 0;
phRow = &hrow;
//====================================================================================
// Use a utility object method to fetch the row with the bookmark.
//====================================================================================
hr = FetchRows(pRowset,hChapter ,lOffset,ONE_ROW, &cRowsObtained, &phRow);
//==========================================================================================
// In case of any problem with fetching the row make an entry
// in the error array.
//==========================================================================================
if (FAILED(hr) || cRowsObtained < ONE_ROW)
{
dbrowstatus = (hr == E_OUTOFMEMORY)
? DBROWSTATUS_E_OUTOFMEMORY
: DBROWSTATUS_E_INVALID;
hrow = DB_NULL_HROW;
}
else
{
prowbuff = pRowset->GetRowBuffFromSlot(hrow);
//==========================================================================
// Now, enter this bookmark in our hashtable.
//==========================================================================
if (SUCCEEDED(hr))
{
prowbuff->cbBmk = BOOKMARKSIZE;
prowbuff->dwBmk = rgcbBookmarks[ibmk];
hr = (pRowset->m_pHashTblBkmark)->InsertFindBmk(FALSE,
hrow, prowbuff->cbBmk, pbBmk, &hrowFound);
if (FAILED(hr))
{
ReleaseSlots(pRowset->m_pIBuffer,hrow, ONE_ROW);
dbrowstatus = DBROWSTATUS_E_OUTOFMEMORY;
hrow = DB_NULL_HROW;
}
else
{
assert(hr == S_FALSE);
dbrowstatus = DBROWSTATUS_S_OK;
}
}
}
}
// mark status.
if (rgRowStatus)
rgRowStatus[ibmk] = dbrowstatus;
if (dbrowstatus != DBROWSTATUS_S_OK)
cErrors++;
// Put the rowhandle in the output array, and
rghRows[ibmk] = (HROW)hrow;
}
// Reverting back the state of the rowset
pRowset->m_lLastFetchPos = ulLastFetchPos;
pRowset->m_FetchDir = lFetchDir;
return
cErrors
? (cErrors < (ULONG)cRows)
? DB_S_ERRORSOCCURRED : DB_E_ERRORSOCCURRED
: S_OK;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Function to fetch the next few rows as requested from the bookmark specified
///////////////////////////////////////////////////////////////////////////////////////////
HRESULT CRowFetchObj::FetchNextRowsByBookMark(CRowset * pRowset,
HCHAPTER hChapter, // IN The Chapter handle.
DBBKMARK cbBookmark, // size of BOOKMARK
const BYTE * pBookmark, // The bookmark from which fetch should start
DBROWOFFSET lRowsOffset,
DBROWCOUNT cRows,
DBCOUNTITEM * pcRowsObtained,
HROW ** prghRows) // array containing the row handles
{
HRESULT hr = S_OK;
//=====================================================================
// Must be a valid bookmark
//=====================================================================
if (cbBookmark != BOOKMARKSIZE && cbBookmark != STD_BOOKMARKLENGTH)
{
hr = DB_E_BADBOOKMARK;
}
else
//=============================================================================
// If the bookmark is a standard bookmark
//=============================================================================
if( cbBookmark == STD_BOOKMARKLENGTH)
{
switch(*pBookmark)
{
case DBBMK_INVALID:
return DB_E_BADBOOKMARK;
case DBBMK_FIRST:
lRowsOffset = lRowsOffset - pRowset->m_lLastFetchPos ;
if(cRows < 0)
{
hr = DB_S_ENDOFROWSET;
}
break;
case DBBMK_LAST:
lRowsOffset = lRowsOffset + pRowset->m_lRowCount - pRowset->m_lLastFetchPos;
if(cRows > 0)
{
hr = DB_S_ENDOFROWSET;
}
break;
}
}
//=============================================================================
// If not a standard bookmark
//=============================================================================
else
{
lRowsOffset = lRowsOffset + (*(ULONG_PTR *)pBookmark - pRowset->m_lLastFetchPos);
// Adjust the offset , so that the first received row is correct
lRowsOffset = cRows > 0 ? lRowsOffset -1 : lRowsOffset + 1;
}
if(hr == S_OK)
{
if( 0 > (LONG)(lRowsOffset + pRowset->m_lLastFetchPos) &&
(lRowsOffset + pRowset->m_lLastFetchPos) > pRowset->m_lRowCount)
{
hr = DB_E_BADSTARTPOSITION;
}
else
{
// NTRaid : 134987
// 07/12/00
ULONG_PTR lPrevPos = pRowset->m_lLastFetchPos;
FETCHDIRECTION lFetchDir = pRowset->GetCurFetchDirection();
// set the direction flag on the enumerator so that the
// enumerator returns instance starting from the last instance
if(cbBookmark == STD_BOOKMARKLENGTH && *pBookmark == DBBMK_LAST)
{
pRowset->SetCurFetchDirection(FETCHDIRFORWARD);
}
//=============================================================================
// call this function to fetch rows
//=============================================================================
if(SUCCEEDED(hr = FetchRows(pRowset,hChapter ,lRowsOffset,cRows, pcRowsObtained, prghRows)))
{
HRESULT hrLocal = S_OK;
// Adjust the position of the enumerator after fetching
ULONG_PTR lOffSetAdjust = lPrevPos -pRowset->m_lLastFetchPos;
if(SUCCEEDED(hrLocal = pRowset->ResetRowsetToNewPosition(lOffSetAdjust,pRowset->m_pInstance)))
{
pRowset->m_lLastFetchPos = lPrevPos;
pRowset->SetCurFetchDirection(lFetchDir);
}
if(FAILED(hrLocal))
{
hr = hrLocal;
}
}
}
}
return hr;
}