Возврат больших данных

В общих случаях потребители должны изолировать код, создающий объект хранилища поставщика OLE DB для собственного клиента SQL Server, от другого кода, обрабатывающего данные, на которые не имеется ссылка указателя интерфейса ISequentialStream.

В этом подразделе описывается функциональность, обеспечиваемая следующими функциями.

  • IRowset:GetData

  • IRow::GetColumns

  • ICommand::Execute

Если свойство DBPROP_ACCESSORDER (в группе свойств набора строк) имеет значение DBPROPVAL_AO_SEQUENTIAL или DBPROPVAL_AO_SEQUENTIALSTORAGEOBJECTS, потребитель должен получать только одну строку данных в вызове метода GetNextRows, поскольку данные BLOB не буферизуются. Если значение свойства DBPROP_ACCESSORDER равно DBPROPVAL_AO_RANDOM, потребитель может получать несколько строк данных в одном вызове метода GetNextRows.

Поставщик OLE DB для собственного клиента SQL Server не получает большие данные из SQL Server, пока этого не запросит потребитель. Потребитель должен связывать все короткие типы данных в методе доступа, а затем, если потребуется использовать один или несколько временных методов доступа для получения значений больших типов данных.

Примеры

Этот пример получает значение большого типа данных из одного столбца:

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    // The SQL Server Native Client OLE DB provider.    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);    }