Obtendo dados grandes

Em geral, os consumidores devem isolar o código que cria um objeto de armazenamento do provedor do OLE DB do SQL Server Native Client do código que trata dados não referenciados por meio de um ponteiro de interface ISequentialStream.

Este tópico aborda a funcionalidade disponível nas funções a seguir:

  • IRowset:GetData

  • IRow::GetColumns

  • ICommand::Execute

Se a propriedade DBPROP_ACCESSORDER (no grupo de propriedades do conjunto de linhas) for definida como um dos valores DBPROPVAL_AO_SEQUENTIAL ou DBPROPVAL_AO_SEQUENTIALSTORAGEOBJECTS, o consumidor deverá buscar somente uma única linha de dados em uma chamada para o método GetNextRows porque os dados BLOB não serão armazenados em buffer. Se o valor de DBPROP_ACCESSORDER for definido como DBPROPVAL_AO_RANDOM, o consumidor poderá buscar várias linhas de dados em GetNextRows.

O provedor do OLE DB do SQL Server Native Client não recupera dados grandes do SQL Server enquanto isso não for solicitado pelo consumidor. O consumidor deve associar todos os dados curtos em um acessador e usar um ou mais acessadores temporários para recuperar valores de dados grandes conforme necessário.

Exemplo

Este exemplo recupera um valor de dados grandes de uma única coluna:

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);
    }