In general, consumers should isolate code that creates a SQLOLEDB storage object from other code that handles data not referenced through an ISequentialStream pointer.
When the consumer indicates a storage object is one member of a row of data values, then the consumer limits its use of storage objects because SQLOLEDB can support only a single open object. In this case, the consumer can fetch only a single row of data in GetNextRows.
SQLOLEDB does not retrieve large data from SQL Server until requested to do so by the consumer. The consumer should bind all short data in one accessor, then use one or more temporary accessors to retrieve large data values as required.
This example retrieves a large data value from a single column.
HRESULT GetUnboundData
(
IRowset* pIRowset,
HROW hRow,
ULONG nCol,
BYTE* pUnboundData
)
{
UINT cbRow = sizeof(IUnknown*) + sizeof(ULONG);
BYTE* pRow = new BYTE[cbRow];
DBOBJECT dbobject;
IAccessor* pIAccessor = NULL;
HACCESSOR haccessor;
DBBINDING dbbinding;
ULONG ulbindstatus;
ULONG dwStatus;
ISequentialStream* pISequentialStream;
ULONG cbRead;
HRESULT hr;
// Set up the DBOBJECT structure.
dbobject.dwFlags = STGM_READ;
dbobject.iid = IID_ISequentialStream;
// Create the DBBINDING, requesting a storage-object pointer from
// SQLOLEDB.
dbbinding.iOrdinal = nCol;
dbbinding.obValue = 0;
dbbinding.obStatus = sizeof(IUnknown*);
dbbinding.obLength = 0;
dbbinding.pTypeInfo = NULL;
dbbinding.pObject = &dbobject;
dbbinding.pBindExt = NULL;
dbbinding.dwPart = DBPART_VALUE | DBPART_STATUS;
dbbinding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
dbbinding.eParamIO = DBPARAMIO_NOTPARAM;
dbbinding.cbMaxLen = 0;
dbbinding.dwFlags = 0;
dbbinding.wType = DBTYPE_IUNKNOWN;
dbbinding.bPrecision = 0;
dbbinding.bScale = 0;
if (FAILED(hr = pIRowset->
QueryInterface(IID_IAccessor, (void**) &pIAccessor)))
{
// Process QueryInterface failure.
return (hr);
}
// Create the accessor.
if (FAILED(hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1,
&dbbinding, 0, &haccessor, &ulbindstatus)))
{
// Process error from CreateAccessor.
pIAccessor->Release();
return (hr);
}
// Read and process BLOCK_SIZE bytes at a time.
if (SUCCEEDED(hr = pIRowset->GetData(hRow, haccessor, pRow)))
{
dwStatus = *((ULONG*) (pRow + dbbinding.obStatus));
if (dwStatus == DBSTATUS_S_ISNULL)
{
// Process NULL data
}
else if (dwStatus == DBSTATUS_S_OK)
{
pISequentialStream = *((ISequentialStream**)
(pRow + dbbinding.obValue));
do
{
if (SUCCEEDED(hr =
pISequentialStream->Read(pUnboundData,
BLOCK_SIZE, &cbRead)))
{
pUnboundData += cbRead;
}
}
while (SUCCEEDED(hr) && cbRead >= BLOCK_SIZE);
pISequentialStream->Release();
}
}
else
{
// Process error from GetData.
}
pIAccessor->ReleaseAccessor(haccessor, NULL);
pIAccessor->Release();
delete [] pRow;
return (hr);
}