When a BLOB is treated as in-memory data, it is sent or retrieved in a single piece of memory. If the consumer allocates the memory for the BLOB, it usually binds the column with a type indicator of DBTYPE_BYTES, DBTYPE_STR, or DBTYPE_WSTR, depending on the data contained in the BLOB. When getting data, if the consumer wants the provider to allocate the memory for the BLOB, it usually binds the column with one of the preceding type indicators combined with DBTYPE_BYREF.
To get the BLOB data, the consumer calls a method such as IRowset::GetData with an accessor containing this binding, and the provider returns the entire contents of the BLOB to the consumer. To set the BLOB data, the consumer calls a method such as IRowsetChange::SetData with an accessor containing this binding and sends the entire contents of the BLOB to the provider. This is no different from binding and getting or setting data in other columns, such as getting or setting data in an integer column. If you get or set character data in this manner, the data is null terminated.
For example, the following code retrieves a 5000-byte BLOB and stores it in consumer memory:
#include<oledb.h>
IMalloc* pIMalloc;
IAccessor* pIAccessor;
IRowset* pIRowset;
int main() {
HACCESSOR hAccessor;
DBBINDSTATUS rgStatus[1];
DBBINDING rgBinding[1] = {
1, // Column 1
0, // Offset to data
5000, // Offset to length
5004, // Offset to status
NULL, // No type info
NULL, // Not an object
NULL, // No binding extensions
DBPART_VALUE|DBPART_LENGTH|DBPART_STATUS, // Bind value, length, status
DBMEMOWNER_CLIENTOWNED, // Memory owned by consumer
DBPARAMIO_NOTPARAM, // Not a parameter
5000, // Max length
0 , // Reserved
DBTYPE_BYTES, // Type DBTYPE_BYTES
0, // Precision not applicable
0 // Scale not applicable
};
pIRowset->QueryInterface(IID_IAccessor, (void**) &pIAccessor);
pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1, rgBinding,
(5000 + sizeof(ULONG) + sizeof(DBSTATUS)), &hAccessor, rgStatus);
pIAccessor->Release();
// Allocate memory for the in-memory data. The first 5000 bytes are for the data,
// the next sizeof(ULONG) bytes are for the length, and the final sizeof(DBSTATUS)
// bytes are for the status.
void * pData = pIMalloc->Alloc(5000 + sizeof(ULONG) + sizeof(DBSTATUS));
// Get the next row, get the data in that row, and process the data. Assume the
// length of the data is known to be <=5000 bytes, so no need to check truncation.
HROW* rghRows = NULL;
ULONG cRows;
pIRowset->GetNextRows(NULL, 0, 1, &cRows, &rghRows);
pIRowset->GetData(rghRows[0], hAccessor, pData);
if ((DBSTATUS)(((BYTE*) pData)[rgBinding[0].obStatus]) == DBSTATUS_S_ISNULL) {
// Process NULL data
} else if ((DBSTATUS)((BYTE*)pData)[rgBinding[0].obStatus] == DBSTATUS_S_OK) {
// Process data. Length is (ULONG)pData[rgBinding[0].obLength].
}
pIMalloc->Free(rghRows);
};