Retrieving Data from the Data Cache
IRowset::GetData enables consumers to retrieve data from the data cache. GetData uses the bindings in the accessor to determine how the data should be returned and what data should be returned to the consumer's buffer. Then, GetData converts the data in the cache to the type specified in the binding and transfers the converted data to the consumer. The source code for IRowset::GetData follows.
Example
// CImpIRowset::GetData -------------
//
// @mfunc Retrieves data from the rowset's cache
//
// @rdesc Returns one of the following values:
// @flag S_OK | Method Succeeded
// @flag DB_S_ERRORSOCCURED | Could not coerce a column value
// @flag DB_E_BADACCESSORHANDLE | Invalid Accessor given
// @flag DB_E_BADROWHANDLE | Invalid row handle given
// @flag E_INVALIDARG | pData was NULL
// @flag OTHER | Other HRESULTs returned by called functions
//
STDMETHODIMP CImpIRowset::GetData
(
HROW hRow, //@parm IN | Row Handle
HACCESSOR hAccessor, //@parm IN | Accessor to use
void *pData //@parm OUT | Pointer to buffer where data should go.
)
{
PACCESSOR pAccessor;
DBORDINAL cCols;
DBORDINAL cBind;
ROWBUFF *pRowBuff;
COLUMNDATA *pColumnData;
DBBINDING *pBinding;
DBCOUNTITEM cBindings;
DBORDINAL cErrorCount;
DBTYPE dwSrcType;
DBTYPE dwDstType;
void *pSrc;
void *pDst;
DBBYTEOFFSET ulSrcLength;
DBLENGTH* pulDstLength;
DBLENGTH cbDstMaxLength;
ULONG dwSrcStatus;
ULONG *pdwDstStatus;
DWORD dwPart;
HRESULT hr;
DBCOLUMNINFO * rgdbcolumninfo = NULL;
// 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 columns retrieved with successful status
// Return DB_S_ERRORSOCCURED on failure to retrieve one or more column values
// Return DB_E_ERRORSOCCURED on failure to retrieve all column values
// 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( m_pObj->m_pextbufferAccessor );
m_pObj->m_pextbufferAccessor->GetItemOfExtBuffer(hAccessor, &pAccessor);
if( !pAccessor )
return DB_E_BADACCESSORHANDLE;
assert( pAccessor );
cBindings = pAccessor->cBindings;
pBinding = pAccessor->rgBindings;
// 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 (m_pObj->m_prowbitsIBuffer->IsSlotSet( (ULONG) hRow ) != S_OK)
return ResultFromScode( DB_E_BADROWHANDLE );
// Ensure a place to put data, unless the accessor is the null accessor then
// a NULL pData is okay.
if ( pData == NULL && cBindings != 0 )
return ResultFromScode( E_INVALIDARG );
// Check to see if we have a DC
if( !g_pIDataConvert)
return (E_FAIL);
// Internal error for a 0 reference count on this row,
// since we depend on the slot-set stuff.
pRowBuff = m_pObj->GetRowBuff( (DBCOUNTITEM) hRow, TRUE );
assert( pRowBuff->ulRefCount );
// Check for the Deleted Row
if ( m_pObj->m_pFileio->IsDeleted( (DBBKMARK) pRowBuff->pbBmk ) == S_OK )
return ResultFromScode( DB_E_DELETEDROW );
cErrorCount = 0;
rgdbcolumninfo = m_pObj->m_pFileio->GetColInfo();
for (cBind=0; cBind < cBindings; cBind++)
{
cCols = pBinding[cBind].iOrdinal;
// make sure column number is in range
if ( !(0 < cCols && cCols <= m_pObj->m_cCols) )
return ResultFromScode( DB_E_BADORDINAL );
pColumnData = m_pObj->m_pFileio->GetColumnData(cCols, pRowBuff);
dwSrcType = rgdbcolumninfo[cCols].wType;
pSrc = &(pColumnData->bData);
ulSrcLength = pColumnData->dwLength;
dwSrcStatus = pColumnData->dwStatus;
cbDstMaxLength = pBinding[cBind].cbMaxLen;
dwDstType = pBinding[cBind].wType;
dwPart = pBinding[cBind].dwPart;
pDst = dwPart & DBPART_VALUE ? ((BYTE *) pData + pBinding[cBind].obValue) : NULL;
pulDstLength = dwPart & DBPART_LENGTH ? (DBLENGTH *) ((BYTE*) pData + pBinding[cBind].obLength) : NULL;
pdwDstStatus = dwPart & DBPART_STATUS ? (ULONG *) ((BYTE*) pData + pBinding[cBind].obStatus) : NULL;
hr = g_pIDataConvert->DataConvert(
dwSrcType,
dwDstType,
ulSrcLength,
pulDstLength,
pSrc,
pDst,
cbDstMaxLength,
dwSrcStatus,
pdwDstStatus,
pBinding[cBind].bPrecision, // bPrecision for conversion to DBNUMERIC
pBinding[cBind].bScale, // bScale for conversion to DBNUMERIC
DBDATACONVERT_DEFAULT);
// rounding or truncation or can't coerce
if (hr != S_OK)
cErrorCount++;
}
// We report any lossy conversions with a special status.
// Note that DB_S_ERRORSOCCURED is a success, rather than failure.
return cErrorCount ? ( cErrorCount < cBindings ) ?
( DB_S_ERRORSOCCURRED ) : ( DB_E_ERRORSOCCURRED ) : ( S_OK );
}