Início Rápido: Conecte-se e consulte com o driver Microsoft OLE DB

Neste quickstart, você constrói um aplicativo de console Windows C++ com Visual Studio 2022 e versões posteriores. O aplicativo se conecta ao Banco de Dados SQL do Azure, ao SQL database no Microsoft Fabric ou ao SQL Server com o Microsoft OLE DB Driver 19 para SQL Server. Ele executa uma consulta parametrizada contra os AdventureWorksLT dados da amostra e verifica o resultado.

Pré-requisitos

Criar um banco de dados SQL

Crie ou conecte-se a um banco de dados SQL em uma das seguintes plataformas:

Para este quickstart, selecione ou carregue os AdventureWorksLT dados da amostra.

Para um contêiner SQL Server, crie o contêiner e carregue os dados de exemplo em um comando:

sqlcmd create mssql --accept-eula --using https://aka.ms/AdventureWorksLT.bak

Para uma instância existente do SQL Server, restaure um AdventureWorksLT backup a partir de bancos de dados de exemplo do AdventureWorks.

O aplicativo cliente OLE DB neste início rápido roda no Windows. Um contêiner do SQL Server pode rodar em outro host suportado.

Verifique o controlador

Abra um prompt de comandos x64 Native Tools para sua versão do Visual Studio e execute o seguinte comando:

Importante

Os comandos neste início rápido usam a sintaxe do Prompt de Comando. Execute-os em um Prompt de Comando do Native Tools para x64, em que o prompt termina com >. Não os execute no PowerShell, onde o prompt começa com PS.

reg query HKCR\MSOLEDBSQL19

O comando exibe o provedor registrado MSOLEDBSQL19 .

Configurar a conexão

Defina OLEDB_CONNECTION_STRING no Prompt de Comando do Native Tools x64. O aplicativo lê a cadeia de conexão do ambiente e não a exibe.

Para Banco de Dados SQL do Azure ou SQL Database no Fabric, use a autenticação interativa do Microsoft Entra. Substitua os marcadores de posição pelo servidor, banco de dados e ID de usuário Microsoft Entra do seu recurso SQL:

set "OLEDB_CONNECTION_STRING=Provider=MSOLEDBSQL19;Data Source=tcp:<server>,1433;Initial Catalog=<database>;Authentication=ActiveDirectoryInteractive;User ID=<user_id>;Use Encryption for Data=Mandatory;Trust Server Certificate=false;"

Para um banco de dados SQL no Fabric, sua identidade precisa da permissão Read para o item de banco de dados. Autenticação SQL não é suportada. Para obter mais informações, consulte Autenticação no banco de dados SQL no Microsoft Fabric.

Para uma instância existente do SQL Server que aceita Autenticação do Windows, use Integrated Security=SSPI:

set "OLEDB_CONNECTION_STRING=Provider=MSOLEDBSQL19;Data Source=tcp:<server>,1433;Initial Catalog=<database>;Integrated Security=SSPI;Use Encryption for Data=Mandatory;Trust Server Certificate=false;"

Para uma instância ou contêiner de SQL Server que aceita autenticação SQL, useAuthentication=SqlPassword:

set "OLEDB_USER_ID=<user_id>"
set "OLEDB_PASSWORD=<password>"
set "OLEDB_CONNECTION_STRING=Provider=MSOLEDBSQL19;Data Source=tcp:<server>,1433;Initial Catalog=<database>;Authentication=SqlPassword;User ID=%OLEDB_USER_ID%;Password=%OLEDB_PASSWORD%;Use Encryption for Data=Mandatory;Trust Server Certificate=false;"

O certificado do SQL Server deve corresponder ao nome do servidor e à cadeia com uma autoridade certificadora (CA) em quem o cliente Windows confia. Para um container SQL Server, configure o Transport Layer Security (TLS) no container e registre a CA emissora no cliente Windows antes de executar a aplicação. Para mais informações, veja Criptografar conexões para SQL Server em Linux e Configurar Mecanismo de Banco de Dados do SQL Server para criptografar conexões.

Criar o aplicativo

  1. Crie um diretório de projetos:

    mkdir oledb-quickstart
    cd oledb-quickstart
    
  2. Crie um arquivo nomeado oledb-quickstart.cpp com o seguinte código:

    #include <windows.h>
    #include <oledb.h>
    #include <msdasc.h>
    #include <msoledbsql.h>
    
    #include <cstddef>
    #include <iomanip>
    #include <iostream>
    #include <string>
    
    template <typename T>
    void Release(T*& pointer)
    {
        if (pointer != nullptr)
        {
            pointer->Release();
            pointer = nullptr;
        }
    }
    
    struct ParameterData
    {
        DBSTATUS status;
        DBLENGTH length;
        LONG value;
    };
    
    constexpr std::size_t productNameCharacters = 51;
    
    struct RowData
    {
        DBSTATUS productIdStatus;
        DBLENGTH productIdLength;
        LONG productId;
        DBSTATUS nameStatus;
        DBLENGTH nameLength;
        wchar_t name[productNameCharacters];
    };
    
    std::wstring ReadEnvironmentVariable(const wchar_t* name)
    {
        const DWORD length = GetEnvironmentVariableW(name, nullptr, 0);
        if (length == 0)
            return {};
    
        std::wstring value(length, L'\0');
        const DWORD copied = GetEnvironmentVariableW(
            name,
            value.data(),
            length);
        if (copied == 0 || copied >= length)
            return {};
    
        value.resize(copied);
        return value;
    }
    
    int wmain()
    {
        const std::wstring connectionString =
            ReadEnvironmentVariable(L"OLEDB_CONNECTION_STRING");
        if (connectionString.empty())
        {
            std::wcerr << L"Set OLEDB_CONNECTION_STRING before running.\n";
            return 1;
        }
    
        HRESULT result = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
        if (FAILED(result))
        {
            std::wcerr << L"COM initialization failed: 0x"
                       << std::hex << result << L'\n';
            return 1;
        }
    
        IDataInitialize* dataInitialize = nullptr;
        IDBInitialize* dbInitialize = nullptr;
        IDBCreateSession* createSession = nullptr;
        IDBCreateCommand* createCommand = nullptr;
        ICommandText* commandText = nullptr;
        ICommandWithParameters* commandParameters = nullptr;
        IAccessor* parameterAccessor = nullptr;
        IRowset* rowset = nullptr;
        IAccessor* rowAccessor = nullptr;
        HACCESSOR parameterHandle = DB_NULL_HACCESSOR;
        HACCESSOR rowHandle = DB_NULL_HACCESSOR;
        HROW* rows = nullptr;
        DBCOUNTITEM rowCount = 0;
        bool initialized = false;
    
        do
        {
            result = CoCreateInstance(
                CLSID_MSDAINITIALIZE,
                nullptr,
                CLSCTX_INPROC_SERVER,
                IID_IDataInitialize,
                reinterpret_cast<void**>(&dataInitialize));
            if (FAILED(result))
                break;
    
            result = dataInitialize->GetDataSource(
                nullptr,
                CLSCTX_INPROC_SERVER,
                connectionString.c_str(),
                IID_IDBInitialize,
                reinterpret_cast<IUnknown**>(&dbInitialize));
            if (FAILED(result))
                break;
    
            result = dbInitialize->Initialize();
            if (FAILED(result))
                break;
            initialized = true;
    
            result = dbInitialize->QueryInterface(
                IID_IDBCreateSession,
                reinterpret_cast<void**>(&createSession));
            if (FAILED(result))
                break;
    
            result = createSession->CreateSession(
                nullptr,
                IID_IDBCreateCommand,
                reinterpret_cast<IUnknown**>(&createCommand));
            if (FAILED(result))
                break;
    
            result = createCommand->CreateCommand(
                nullptr,
                IID_ICommandText,
                reinterpret_cast<IUnknown**>(&commandText));
            if (FAILED(result))
                break;
    
            result = commandText->SetCommandText(
                DBGUID_DBSQL,
                const_cast<wchar_t*>(
                    L"SELECT TOP (5) ProductID, Name "
                    L"FROM SalesLT.Product "
                    L"WHERE ProductID > ? "
                    L"ORDER BY ProductID;"));
            if (FAILED(result))
                break;
    
            result = commandText->QueryInterface(
                IID_ICommandWithParameters,
                reinterpret_cast<void**>(&commandParameters));
            if (FAILED(result))
                break;
    
            DB_UPARAMS parameterOrdinal = 1;
            wchar_t parameterType[] = L"int";
            DBPARAMBINDINFO parameterInfo = {};
            parameterInfo.pwszDataSourceType = parameterType;
            parameterInfo.ulParamSize = sizeof(LONG);
            parameterInfo.dwFlags = DBPARAMFLAGS_ISINPUT;
            parameterInfo.bPrecision = 10;
    
            result = commandParameters->SetParameterInfo(
                1,
                &parameterOrdinal,
                &parameterInfo);
            if (FAILED(result))
                break;
    
            result = commandText->QueryInterface(
                IID_IAccessor,
                reinterpret_cast<void**>(&parameterAccessor));
            if (FAILED(result))
                break;
    
            DBBINDING parameterBinding = {};
            parameterBinding.iOrdinal = 1;
            parameterBinding.obStatus = offsetof(ParameterData, status);
            parameterBinding.obLength = offsetof(ParameterData, length);
            parameterBinding.obValue = offsetof(ParameterData, value);
            parameterBinding.dwPart = DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE;
            parameterBinding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
            parameterBinding.eParamIO = DBPARAMIO_INPUT;
            parameterBinding.cbMaxLen = sizeof(LONG);
            parameterBinding.wType = DBTYPE_I4;
            parameterBinding.bPrecision = 10;
    
            DBBINDSTATUS parameterBindStatus = DBBINDSTATUS_OK;
            result = parameterAccessor->CreateAccessor(
                DBACCESSOR_PARAMETERDATA,
                1,
                &parameterBinding,
                sizeof(ParameterData),
                &parameterHandle,
                &parameterBindStatus);
            if (FAILED(result) || parameterBindStatus != DBBINDSTATUS_OK)
            {
                if (SUCCEEDED(result))
                    result = E_FAIL;
                break;
            }
    
            ParameterData parameter = {
                DBSTATUS_S_OK,
                sizeof(LONG),
                0
            };
            DBPARAMS parameters = {
                &parameter,
                1,
                parameterHandle
            };
    
            result = commandText->Execute(
                nullptr,
                IID_IRowset,
                &parameters,
                nullptr,
                reinterpret_cast<IUnknown**>(&rowset));
            if (FAILED(result))
                break;
    
            result = rowset->QueryInterface(
                IID_IAccessor,
                reinterpret_cast<void**>(&rowAccessor));
            if (FAILED(result))
                break;
    
            DBBINDING rowBindings[2] = {};
            rowBindings[0].iOrdinal = 1;
            rowBindings[0].obStatus = offsetof(RowData, productIdStatus);
            rowBindings[0].obLength = offsetof(RowData, productIdLength);
            rowBindings[0].obValue = offsetof(RowData, productId);
            rowBindings[0].dwPart =
                DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE;
            rowBindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
            rowBindings[0].eParamIO = DBPARAMIO_NOTPARAM;
            rowBindings[0].cbMaxLen = sizeof(LONG);
            rowBindings[0].wType = DBTYPE_I4;
            rowBindings[0].bPrecision = 10;
    
            rowBindings[1].iOrdinal = 2;
            rowBindings[1].obStatus = offsetof(RowData, nameStatus);
            rowBindings[1].obLength = offsetof(RowData, nameLength);
            rowBindings[1].obValue = offsetof(RowData, name);
            rowBindings[1].dwPart =
                DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE;
            rowBindings[1].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
            rowBindings[1].eParamIO = DBPARAMIO_NOTPARAM;
            rowBindings[1].cbMaxLen =
                productNameCharacters * sizeof(wchar_t);
            rowBindings[1].wType = DBTYPE_WSTR;
    
            DBBINDSTATUS rowBindStatus[2] = {
                DBBINDSTATUS_OK,
                DBBINDSTATUS_OK
            };
            result = rowAccessor->CreateAccessor(
                DBACCESSOR_ROWDATA,
                2,
                rowBindings,
                sizeof(RowData),
                &rowHandle,
                rowBindStatus);
            if (FAILED(result) ||
                rowBindStatus[0] != DBBINDSTATUS_OK ||
                rowBindStatus[1] != DBBINDSTATUS_OK)
            {
                if (SUCCEEDED(result))
                    result = E_FAIL;
                break;
            }
    
            DBCOUNTITEM productsPrinted = 0;
            while (true)
            {
                result = rowset->GetNextRows(
                    DB_NULL_HCHAPTER,
                    0,
                    1,
                    &rowCount,
                    &rows);
                if (FAILED(result) || rowCount == 0)
                    break;
    
                RowData row = {};
                result = rowset->GetData(rows[0], rowHandle, &row);
                if (FAILED(result) ||
                    row.productIdStatus != DBSTATUS_S_OK ||
                    row.productIdLength != sizeof(LONG) ||
                    row.nameStatus != DBSTATUS_S_OK ||
                    row.nameLength == 0 ||
                    row.nameLength % sizeof(wchar_t) != 0 ||
                    row.nameLength >= sizeof(row.name))
                {
                    result = E_FAIL;
                    break;
                }
                row.name[row.nameLength / sizeof(wchar_t)] = L'\0';
    
                if (productsPrinted == 0)
                {
                    std::wcout << L"Connected with MSOLEDBSQL19.\n\n";
                    std::wcout << std::left
                               << std::setw(12) << L"Product ID"
                               << L"Name\n";
                    std::wcout << std::setw(12) << L"----------"
                               << L"----\n";
                }
    
                std::wcout << std::left
                           << std::setw(12) << row.productId
                           << row.name << L'\n';
                ++productsPrinted;
    
                result = rowset->ReleaseRows(
                    rowCount,
                    rows,
                    nullptr,
                    nullptr,
                    nullptr);
                CoTaskMemFree(rows);
                rows = nullptr;
                rowCount = 0;
                if (FAILED(result))
                    break;
            }
    
            if (FAILED(result))
                break;
            if (productsPrinted == 0)
            {
                result = E_FAIL;
                break;
            }
        }
        while (false);
    
        if (rows != nullptr)
        {
            if (rowset != nullptr && rowCount != 0)
                rowset->ReleaseRows(rowCount, rows, nullptr, nullptr, nullptr);
            CoTaskMemFree(rows);
        }
        if (rowHandle != DB_NULL_HACCESSOR && rowAccessor != nullptr)
            rowAccessor->ReleaseAccessor(rowHandle, nullptr);
        if (parameterHandle != DB_NULL_HACCESSOR && parameterAccessor != nullptr)
            parameterAccessor->ReleaseAccessor(parameterHandle, nullptr);
    
        Release(rowAccessor);
        Release(rowset);
        Release(parameterAccessor);
        Release(commandParameters);
        Release(commandText);
        Release(createCommand);
        Release(createSession);
        if (initialized)
            dbInitialize->Uninitialize();
        Release(dbInitialize);
        Release(dataInitialize);
        CoUninitialize();
    
        if (FAILED(result))
        {
            std::wcerr << L"OLE DB operation failed: 0x"
                       << std::hex << result << L'\n';
            return 1;
        }
    
        return 0;
    }
    

A cadeia de conexão é passada para IDataInitialize::GetDataSource. Esta API usa os nomes-chave Use Encryption for Data espaçados e Trust Server Certificate. As strings de conexão solicitam criptografia e exigem validação de certificado.

A consulta usa um ponto de interrogação como marcador de parâmetro. A aplicação associa o ID mínimo do produto 0 como um int do SQL Server, lê até cinco linhas de SalesLT.Product e imprime o ID e o nome do produto.

Compile e execute o aplicativo

  1. No mesmo Prompt de Comando Nativo de Ferramentas x64, localize o arquivo de cabeçalho do SDK do OLE DB instalado e armazene o diretório dele em OLEDB_INCLUDE:

    for /f "delims=" %i in ('where /r "%ProgramFiles%\Microsoft SQL Server\Client SDK\OLEDB" msoledbsql.h') do for %j in ("%~dpi.") do set "OLEDB_INCLUDE=%~fj"
    
  2. Exiba o diretório selecionado e verifique se ele contém o cabeçalho:

    echo %OLEDB_INCLUDE%
    dir "%OLEDB_INCLUDE%\msoledbsql.h"
    
  3. Compile o aplicativo:

    cl /std:c++17 /EHsc /W4 /I"%OLEDB_INCLUDE%" oledb-quickstart.cpp /link ole32.lib oleaut32.lib
    
  4. Execute o aplicativo:

    oledb-quickstart.exe
    
  5. Limpe a cadeia de conexão no Prompt de Comando atual:

    set OLEDB_CONNECTION_STRING=
    set OLEDB_USER_ID=
    set OLEDB_PASSWORD=
    

As linhas de produtos podem variar conforme a versão do AdventureWorksLT. A saída é semelhante ao exemplo a seguir:

Connected with MSOLEDBSQL19.

Product ID  Name
----------  ----
680         HL Road Frame - Black, 58
706         HL Road Frame - Red, 58
707         Sport-100 Helmet, Red
708         Sport-100 Helmet, Black
709         Mountain Bike Socks, M