Microsoft ODBC Driver para SQL Server

Baixar driver ODBC

ODBC é uma interface nativa de programação de aplicativos (API) para acesso a dados para aplicativos escritos em C e C++. O Microsoft ODBC Driver for SQL Server conecta-se ao SQL Server, Banco de Dados SQL do Azure, Instância Gerenciada de SQL do Azure, Azure Synapse Analytics e banco de dados SQL no Microsoft Fabric. Para as versões de banco de dados que cada versão de driver suporta, veja compatibilidade de versões SQL.

Sua aplicação chama o gerenciador de drivers ODBC, que carrega o driver e passa chamadas ODBC para ele. Use o Gerenciador de Drivers ODBC do Windows no Windows e o unixODBC no Linux e macOS.

Outros idiomas que usam o ODBC incluem COBOL, Perl, PHP e Python. ODBC é amplamente utilizado em cenários de integração de dados, e os drivers Microsoft para PHP para SQL Server são construídos sobre esse driver.

A variante ODBC do sqlcmd e o utilitário bcp usam esse driver, mas são instalados separadamente: o pacote mssql-tools18 no Linux e macOS, e as Utilidades de Linha de Comando da Microsoft no Windows. A variante Go do sqlcmd não usa esse driver. Use sqlcmd para executar instruções Transact-SQL (T-SQL), procedimentos do sistema e arquivos de script. Use o BCP para copiar dados em massa entre uma instância do SQL Server e um arquivo de dados, em qualquer direção.

Escolha o ponto de partida

Linha de base de produção para SQL do Azure

Use este programa completo em C++17 como ponto de partida para um aplicativo hospedado no Azure. Conecta, roda SELECT 1, verifica o resultado e libera os handles ODBC. Instale o Driver 18 e os arquivos de desenvolvimento ODBC da plataforma antes de compilá-lo. Para os pré-requisitos, veja Desenvolver aplicações em C e C++ com o driver ODBC.

Defina ODBC_CONNECTION_STRING no ambiente da aplicação para sua cadeia de conexão completa. O exemplo a seguir utiliza uma identidade gerenciada atribuída ao sistema. O host deve ter essa identidade ativada, e o banco de dados deve conceder acesso a ela. Para requisitos de host, identidades atribuídas pelo usuário e autenticação de desenvolvimento local, veja Use o Microsoft Entra ID com o driver ODBC.

Driver={ODBC Driver 18 for SQL Server};Server=tcp:<server>.database.windows.net,1433;Database=<database>;Authentication=ActiveDirectoryMsi;Encrypt=strict;ConnectRetryCount=3;ConnectRetryInterval=2;

Encrypt=strict requer um endpoint que suporte o Tabular Data Stream (TDS) 8.0. Caso contrário, use Encrypt=yes;TrustServerCertificate=no. Configure um certificado no qual o cliente confie e cujo nome corresponda ao nome do servidor. Para configuração e verificação, veja Solução de problemas de criptografia de conexão.

Mantenha credenciais fora dos arquivos fonte e do histórico da shell. Para ver os comandos para definir a variável de ambiente, veja Configurar a conexão. No Linux e macOS, forneça seu valor como UTF-8. Salve o programa a seguir com o nome odbc-baseline.cpp:

#ifdef _WIN32
#include <windows.h>
#else
#include <iconv.h>
#endif
#include <sql.h>
#include <sqlext.h>

#include <chrono>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <random>
#include <stdexcept>
#include <string>
#include <thread>
#include <vector>

struct Handles {
    SQLHENV env = SQL_NULL_HENV;
    SQLHDBC dbc = SQL_NULL_HDBC;
    SQLHSTMT stmt = SQL_NULL_HSTMT;
    bool connected = false;

    ~Handles() {
        if (stmt) SQLFreeHandle(SQL_HANDLE_STMT, stmt);
        if (connected) SQLDisconnect(dbc);
        if (dbc) SQLFreeHandle(SQL_HANDLE_DBC, dbc);
        if (env) SQLFreeHandle(SQL_HANDLE_ENV, env);
    }
};

bool logDiagnostics(SQLSMALLINT type, SQLHANDLE handle) {
    bool retry = false;
    bool permanent = false;
    for (SQLSMALLINT record = 1; ; ++record) {
        SQLWCHAR state[6] = {};
        SQLWCHAR message[1024] = {};
        SQLINTEGER native = 0;
        SQLRETURN rc = SQLGetDiagRecW(type, handle, record, state, &native,
                                     message, 1024, nullptr);
        if (rc == SQL_NO_DATA) break;
        if (!SQL_SUCCEEDED(rc)) {
            std::cerr << "event=diagnostics_failed rc=" << rc << '\n';
            return false;
        }
        std::string sqlstate;
        for (int i = 0; i < 5; ++i) {
            sqlstate += static_cast<char>(state[i]);
        }
        std::cerr << "event=odbc_diagnostic sqlstate=" << sqlstate
                  << " native_error=" << native << '\n';
        permanent |= sqlstate.substr(0, 2) == "28" ||
                     sqlstate.substr(0, 2) == "IM" ||
                     sqlstate == "HY024" || sqlstate == "HY092";
        retry |= sqlstate == "08S01" || sqlstate == "HYT00" ||
                 sqlstate == "HYT01";
        switch (native) {
            case 10928: case 10929: case 10936:
            case 40197: case 40501: case 40613:
            case 49918: case 49919: case 49920:
                retry = true;
        }
    }
    return retry && !permanent;
}

void requireSuccess(SQLRETURN rc, SQLSMALLINT type, SQLHANDLE handle,
                    const char* operation) {
    if (rc == SQL_SUCCESS) return;
    logDiagnostics(type, handle);
    if (!SQL_SUCCEEDED(rc)) throw std::runtime_error(operation);
}

std::vector<SQLWCHAR> readConnectionString() {
    static_assert(sizeof(SQLWCHAR) == 2, "Use a driver manager with 16-bit SQLWCHAR");
#ifdef _WIN32
    size_t length = 0;
    if (_wgetenv_s(&length, nullptr, 0, L"ODBC_CONNECTION_STRING") != 0 ||
        length == 0) {
        throw std::runtime_error("ODBC_CONNECTION_STRING is required");
    }
    std::vector<wchar_t> raw(length);
    if (_wgetenv_s(&length, raw.data(), raw.size(), L"ODBC_CONNECTION_STRING") != 0) {
        throw std::runtime_error("Cannot read ODBC_CONNECTION_STRING");
    }
    std::vector<SQLWCHAR> result(raw.begin(), raw.end() - 1);
#else
    const char* raw = std::getenv("ODBC_CONNECTION_STRING");
    if (!raw) throw std::runtime_error("ODBC_CONNECTION_STRING is required");
    iconv_t converter = iconv_open("UTF-16LE", "UTF-8");
    if (converter == reinterpret_cast<iconv_t>(-1)) {
        throw std::runtime_error("Cannot create UTF-8 converter");
    }
    size_t inputBytes = std::strlen(raw);
    std::vector<SQLWCHAR> result(inputBytes + 1);
    char* input = const_cast<char*>(raw);
    char* output = reinterpret_cast<char*>(result.data());
    size_t outputBytes = result.size() * sizeof(SQLWCHAR);
    const size_t capacity = outputBytes;
    size_t status = iconv(converter, &input, &inputBytes, &output, &outputBytes);
    int closeStatus = iconv_close(converter);
    if (status == static_cast<size_t>(-1) || inputBytes != 0 || closeStatus != 0) {
        throw std::runtime_error("ODBC_CONNECTION_STRING must be valid UTF-8");
    }
    result.resize((capacity - outputBytes) / sizeof(SQLWCHAR));
#endif
    if (result.empty() || result.size() >= 32767) {
        throw std::runtime_error("Invalid ODBC_CONNECTION_STRING length");
    }
    result.push_back(0);
    return result;
}

void connectWithRetry(SQLHDBC dbc, std::vector<SQLWCHAR>& connectionString) {
    constexpr int maxAttempts = 4;
    std::mt19937 random{std::random_device{}()};
    std::uniform_int_distribution<int> jitter{0, 250};
    for (int attempt = 1; attempt <= maxAttempts; ++attempt) {
        requireSuccess(SQLSetConnectAttr(
            dbc, SQL_ATTR_LOGIN_TIMEOUT,
            reinterpret_cast<SQLPOINTER>(std::uintptr_t{30}), 0),
            SQL_HANDLE_DBC, dbc, "Set login timeout");
        SQLRETURN rc = SQLDriverConnectW(
            dbc, nullptr, connectionString.data(), SQL_NTS,
            nullptr, 0, nullptr, SQL_DRIVER_NOPROMPT);
        if (SQL_SUCCEEDED(rc)) {
            if (rc == SQL_SUCCESS_WITH_INFO) logDiagnostics(SQL_HANDLE_DBC, dbc);
            std::cout << "event=connected attempt=" << attempt << '\n';
            return;
        }
        bool transient = logDiagnostics(SQL_HANDLE_DBC, dbc);
        if (!transient || attempt == maxAttempts) {
            throw std::runtime_error("Connect failed");
        }
        auto delay = std::chrono::milliseconds{
            (1 << (attempt - 1)) * 10000 + jitter(random)};
        std::cerr << "event=connect_retry attempt=" << attempt
                  << " delay_ms=" << delay.count() << '\n';
        std::this_thread::sleep_for(delay);
    }
}

int main() {
    try {
        auto connectionString = readConnectionString();
        Handles handles;
        if (!SQL_SUCCEEDED(SQLAllocHandle(
                SQL_HANDLE_ENV, SQL_NULL_HANDLE, &handles.env))) {
            throw std::runtime_error("Allocate environment");
        }
        requireSuccess(SQLSetEnvAttr(
            handles.env, SQL_ATTR_ODBC_VERSION,
            reinterpret_cast<SQLPOINTER>(std::uintptr_t{SQL_OV_ODBC3}), 0),
            SQL_HANDLE_ENV, handles.env, "Set ODBC version");
        requireSuccess(SQLAllocHandle(SQL_HANDLE_DBC, handles.env, &handles.dbc),
                       SQL_HANDLE_ENV, handles.env, "Allocate connection");
        connectWithRetry(handles.dbc, connectionString);
        handles.connected = true;
        requireSuccess(SQLAllocHandle(SQL_HANDLE_STMT, handles.dbc, &handles.stmt),
                       SQL_HANDLE_DBC, handles.dbc, "Allocate statement");
        requireSuccess(SQLSetStmtAttr(
            handles.stmt, SQL_ATTR_QUERY_TIMEOUT,
            reinterpret_cast<SQLPOINTER>(std::uintptr_t{10}), 0),
            SQL_HANDLE_STMT, handles.stmt, "Set query timeout");
        SQLWCHAR query[] = {'S', 'E', 'L', 'E', 'C', 'T', ' ', '1', 0};
        requireSuccess(SQLExecDirectW(handles.stmt, query, SQL_NTS),
                       SQL_HANDLE_STMT, handles.stmt, "Execute probe");
        requireSuccess(SQLFetch(handles.stmt),
                       SQL_HANDLE_STMT, handles.stmt, "Fetch probe");
        SQLINTEGER value = 0;
        SQLLEN indicator = 0;
        requireSuccess(SQLGetData(handles.stmt, 1, SQL_C_SLONG,
                                 &value, sizeof(value), &indicator),
                       SQL_HANDLE_STMT, handles.stmt, "Read probe");
        if (indicator == SQL_NULL_DATA || value != 1) {
            throw std::runtime_error("Unexpected probe result");
        }
        std::cout << "event=ready result=" << value << '\n';
        return 0;
    } catch (const std::exception& error) {
        std::cerr << "event=failed operation=\"" << error.what() << "\"\n";
        return 1;
    }
}

O programa solicita um tempo de espera de conexão de 30 segundos para cada uma das no máximo quatro tentativas de conexão e um tempo de consulta de 10 segundos. Entre tentativas transitórias de conexão com falha, ele espera 10, 20 e 40 segundos, cada um com 0 a 250 milissegundos de jitter aleatório. Esses limites não impõem um prazo geral rígido para a autenticação. O exemplo classifica erros de conexão transitória selecionados; adapte a política à sua carga de trabalho com o catálogo de erros de falha transitória do SQL do Azure. Ele não tenta novamente comandos de aplicação nem gravações.

ConnectRetryCount e ConnectRetryInterval configuram a resiliência de conexão para conexões elegíveis que caem enquanto estão ociosas. Eles não tentam a conexão inicial nem reexecutam os comandos do aplicativo. Mantenha os atrasos de recuperação de inatividade mais curtos que o tempo de espera da sua consulta. A amostra registra valores SQLSTATE e números nativos de erro em vez de strings de conexão ou mensagens de diagnóstico completas. Se precisar de texto de mensagem para solucionar o problema, capture isso em um log de diagnóstico protegido.

Construa e execute a baseline

Use um ambiente de compilador que combine com a arquitetura do processador da sua aplicação. No Windows, execute os comandos no Developer PowerShell para Visual Studio. No Linux e macOS, use um shell com seu compilador e arquivos de desenvolvimento unixODBC disponíveis.

cl /nologo /std:c++17 /EHsc /W4 odbc-baseline.cpp odbc32.lib
.\odbc-baseline.exe

Uma primeira conexão bem-sucedida imprime a seguinte saída. Registros diagnósticos adicionais também podem aparecer.

event=connected attempt=1
event=ready result=1

Limpe ODBC_CONNECTION_STRING quando terminar: use Remove-Item Env:\ODBC_CONNECTION_STRING no PowerShell, ou unset ODBC_CONNECTION_STRING no Bash ou Zsh.

Para ouvintes de grupos de disponibilidade e configurações de failover, use Alta disponibilidade e recuperação de desastres.

Características principais

  • Multiplataforma: A mesma API no Windows, Linux e macOS.
  • Autenticação Microsoft Entra ID: Identidade gerenciada, principal de serviço e autenticação integrada, além de autenticação interativa no Windows. Os métodos disponíveis dependem do host e da configuração do banco de dados.
  • Criptografia rigorosa: conexões TDS 8.0 com validação completa de certificados na versão 18 e versões posteriores.
  • Always Encrypted: Criptografia do lado do cliente para colunas sensíveis, com suporte a provedores de keystore personalizados.
  • Resiliência da conexão: Restauração transparente de uma conexão que caiu enquanto estava ociosa.
  • Alta disponibilidade: Disponibilidade de apoio ao ouvinte em grupo com MultiSubnetFailover.
  • Classificação de dados: Metadados de sensibilidade para colunas classificadas.
  • Tipo de dado vetorial: Suporte nativo para o tipo vetorial .
  • Transações distribuídas: suporte a transações XA por meio do Coordenador de Transações Distribuídas da Microsoft (MSDTC).
  • Ferramentas complementares: sqlcmd e bcp, instalados separadamente.

Introdução

Artigo Description
Baixar o driver ODBC para SQL Server Instaladores e pacotes para baixar para cada versão de driver suportada, em todas as três plataformas.
Desenvolver aplicações em C e C++ com o driver ODBC Quais cabeçalhos incluir, em qual ordem, quais bibliotecas vincular e como escolher entre execução assíncrona e threads.
Conecte-se e consulte um banco de dados com C++ Um exemplo completo em C++ que conecta, executa uma consulta e lê resultados, para que você possa confirmar sua configuração de ponta a ponta.
Ciclo de vida do suporte Quais versões de drivers ainda são suportadas e a data em que cada uma sai do suporte.
Principais diferenças de versão O que quebra quando você passa da versão 17 para a versão 18, começando com a mudança na configuração padrão de criptografia.

Instalar o driver

Artigo Description
Requisitos do sistema, instalação e arquivos de driver (Windows) Versões do Windows compatíveis, a linha de comando do instalador para implantação silenciosa e onde cada arquivo de driver é armazenado no disco.
Requisitos do sistema (Linux e macOS) Quais distribuições Linux e versões do macOS cada versão de driver suportam, além da compatibilidade com versões do SQL Server.
Instale o driver ODBC no Linux Etapas do gerenciador de pacotes para Alpine, Debian, Red Hat, SUSE, Ubuntu e Azure Linux, além da instalação offline e da localização dos arquivos dos drivers.
Instale o driver ODBC no macOS Etapas de tap e fórmula do Homebrew para macOS, incluindo como instalar as versões 18, 17 ou 13.1.
Instale o gerenciador de drivers unixODBC (Linux e macOS) Instale ou atualize o unixODBC, o gerenciador de drivers que carrega o driver ODBC no Linux e macOS.

Configuração e conexão

Artigo Description
Atributos e palavras-chave da cadeia de conexão e DSN O catálogo completo de palavras-chave da cadeia de conexão, entradas DSN e atributos SQLSetConnectAttr, com os valores aceitos para cada um deles.
Palavras-chave de string de conexão e nomes de fontes de dados (Linux e macOS) Como odbc.ini e odbcinst.ini definem uma DSN no Linux e macOS, além das configurações de Segurança da Camada de Transporte (TLS) e Protocolo de Controle de Transmissão (TCP) específicas para essas plataformas.
Administrador de Fonte de Dados ODBC DSN (Windows) Configure uma fonte de dados pela interface do usuário do Windows em vez de uma cadeia de conexão.
Pool de conexões com reconhecimento de driver (Windows) Quais palavras-chave e atributos da cadeia de conexão colocam uma conexão em seu próprio pool, e quais exigem uma ida e volta adicional para serem redefinidos.

Autenticar e proteger

Artigo Description
Usar Microsoft Entra ID com o driver ODBC Cada valor de palavra-chave Authentication, de identidade gerenciada e entidade de serviço até interativo e integrado, com a configuração que cada um precisa.
Usar Always Encrypted com o driver ODBC Criptografe valores sensíveis de colunas antes de enviá-los para o banco de dados; consulte o resumo da API do driver e as limitações documentadas.
Classificação de dados Leia os rótulos de sensibilidade que o servidor atribui às colunas classificadas, para que sua aplicação possa aplicar sua própria política de proteção de dados.
Usar autenticação integrada (Linux e macOS) Configure o Kerberos para que um cliente Linux ou macOS possa se conectar com credenciais do Windows em vez de um login do SQL Server.

Alta disponibilidade e resiliência

Artigo Description
Resiliência de conexão Como ConnectRetryCount e ConnectRetryInterval restauram uma conexão quando o servidor a interrompe por inatividade, e os erros IMCxx que o driver retorna quando a recuperação não é possível.
Alta disponibilidade e recuperação de desastre Conecte-se por meio de um listener de grupo de disponibilidade e use MultiSubnetFailover para que o failover não fique bloqueado por um tempo limite da sub-rede.
Use resolução IP de rede transparente Como o fallback legado TransparentNetworkIPResolution ordena as tentativas de conexão através de múltiplos endereços de Protocolo de Internet (IP) e por que MultiSubnetFailover o substitui.

Trabalhar com dados

Artigo Description
Tipo de dados de vetor Vincule, envie e recupere o tipo vetorial , incluindo sua representação nativa em C e suporte a cópias em massa.
Use transações XA com DTC Insale o SQL Server em uma transação distribuída através do Coordenador de Transações Distribuídas da Microsoft no Windows, Linux ou macOS.
Diretrizes de programação (Linux e macOS) Encontre orientações de programação para Linux e macOS, incluindo status de recursos, considerações sobre conjuntos de caracteres, OpenSSL e Alpine Linux.

Diagnosticar e solucionar problemas

Artigo Description
Solução de problemas de criptografia de conexão Corrija os erros de certificado e de criptografia que a versão 18 gera porque criptografa por padrão.
Rastreamento de acesso a dados (Linux e macOS) Ative o rastreamento de motoristas e capture um arquivo de log quando precisar ver as chamadas que seu aplicativo realmente faz.
Problemas conhecidos (Linux e macOS) Defeitos confirmados e suas soluções alternativas. Confira aqui antes de abrir um chamado de suporte.
Perguntas frequentes (Linux e macOS) Respostas curtas para as perguntas que mais surgem sobre o driver no Linux e macOS.

Notas de lançamento e correções de bugs

Artigo Description
Notas de lançamento para Windows Novos recursos, mudanças de comportamento e correções em cada versão do driver do Windows.
Notas de lançamento para Linux e macOS Novos recursos, mudanças de comportamento e correções em cada lançamento de drivers para Linux e macOS.
Notas de atualização para as ferramentas do SQL Server Alterações nas utilidades sqlcmd e bcp , que são instaladas separadamente do driver no Linux e macOS.

Reference

Artigo Description
Driver ODBC no Windows Um resumo versão por versão do que o driver suporta no Windows e um índice dos artigos específicos do Windows.
Recursos do driver ODBC no Windows Qual versão introduziu cada recurso do Windows, além das mudanças de comportamento que vieram junto.

Solicitar um recurso

Para solicitar uma funcionalidade, envie uma ideia por meio do feedback do SQL Server.