Driver ODBC da Microsoft para SQL Server

Baixar driver ODBC

ODBC é uma interface nativa de programação de aplicações para acesso a dados (API) para aplicações escritas em C e C++. O Microsoft ODBC Driver for SQL Server estabelece ligação ao SQL Server, ao Base de Dados SQL do Azure, ao Azure SQL Managed Instance, ao Azure Synapse Analytics e à base de dados SQL do Microsoft Fabric. Para as versões da base de dados que cada versão de driver suporta, consulte compatibilidade de versões SQL.

A sua aplicação chama o gestor de drivers ODBC, que carrega o driver e passa as chamadas ODBC para ele. Use o Windows ODBC Driver Manager no Windows e o unixODBC no Linux e macOS.

Outras linguagens que podem usar ODBC incluem COBOL, Perl, PHP e Python. O 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 este driver.

A variante ODBC do sqlcmd e a utilidade bcp usam este driver, mas instalam-se separadamente: o mssql-tools18 pacote no Linux e macOS, e as Utilidades de Linha de Comando da Microsoft no Windows. A variante Go do sqlcmd não usa este driver. Utilize sqlcmd para executar instruções Transact-SQL (T-SQL), procedimentos do sistema e ficheiros de script. Use bcp para copiar dados em massa entre uma instância do SQL Server e um ficheiro de dados, em qualquer das direções.

Escolhe o teu ponto de partida

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

Use este programa completo em C++17 como ponto de partida para uma aplicação alojada no Azure. Estabelece a ligação, executa SELECT 1, verifica o resultado e liberta os handles ODBC. Instale o Driver 18 e os ficheiros de desenvolvimento ODBC da plataforma antes de o compilar. Para pré-requisitos, consulte Desenvolver aplicações C e C++ com o driver ODBC.

Defina ODBC_CONNECTION_STRING no ambiente da aplicação como a sua cadeia de ligação completa. O exemplo seguinte utiliza uma identidade gerida atribuída pelo sistema. O anfitrião deve ter essa identidade ativada, e a base de dados deve conceder-lhe acesso. Para requisitos de host, identidades atribuídas pelo utilizador e autenticação de desenvolvimento local, veja Use 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 requerem um endpoint que suporte o Tabular Data Stream (TDS) 8.0. Caso contrário, use Encrypt=yes;TrustServerCertificate=no. Configure um certificado em que o cliente confie e cujo nome corresponda ao do servidor. Para configuração e verificação, veja Resolução de problemas de encriptação de ligação.

Mantenha as credenciais fora dos ficheiros de origem e do histórico do shell. Para ver os comandos para definir a variável de ambiente, consulte Configurar a conexão. No Linux e macOS, indique o seu valor como UTF-8. Guardar o seguinte programa como 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 timeout de ligação de 30 segundos para cada uma de, no máximo, quatro tentativas de ligação e um timeout de consulta de 10 segundos. Entre tentativas falhadas de ligação transitória, espera 10, 20 e 40 segundos, cada uma com 0 a 250 milissegundos de jitter aleatório. Estes limites não impõem um prazo global rígido para a autenticação. O exemplo classifica erros selecionados de ligação transitória; adapta a política à sua carga de trabalho com o catálogo de erros de falha transitória do SQL do Azure. Não tenta novamente comandos de aplicação nem operações de escrita.

ConnectRetryCount e ConnectRetryInterval configuram a resiliência da ligação para ligações elegíveis que caem enquanto estão inativas. Eles não tentam novamente a conexão inicial nem reexecutam os comandos da aplicação. Mantenha os atrasos de recuperação em repouso mais curtos do que o tempo limite da sua consulta. A amostra regista valores SQLSTATE e números de erro nativos em vez de cadeias de ligação ou mensagens de diagnóstico completas. Se precisares de texto da mensagem para resolução de problemas, regista-o num registo de diagnóstico protegido.

Constrói e executa a baseline

Utilize um ambiente de compilador que corresponda à arquitetura do processador da sua aplicação. No Windows, execute os comandos no Developer PowerShell para Visual Studio. No Linux e macOS, usa um shell com o compilador e os ficheiros de desenvolvimento unixODBC disponíveis.

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

Uma primeira ligação bem-sucedida imprime a seguinte saída. Podem também surgir registos diagnósticos adicionais.

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

Limpa ODBC_CONNECTION_STRING quando terminares: usa Remove-Item Env:\ODBC_CONNECTION_STRING no PowerShell, ou unset ODBC_CONNECTION_STRING no Bash ou Zsh.

Para escutas de grupos de disponibilidade e definições de failover, use Alta disponibilidade e recuperação após desastre.

Principais características

  • Multiplataforma: A mesma API no Windows, Linux e macOS.
  • Autenticação Microsoft Entra ID: Identidade gerida, 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 da base de dados.
  • Encriptação rigorosa: ligações TDS 8.0 com validação completa de certificados na versão 18 e versões posteriores.
  • Always Encrypted: Encriptação do lado do cliente para colunas sensíveis, com suporte para provedores personalizados de arquivo de chaves.
  • Resiliência da ligação: Restauração transparente de uma ligação que caiu enquanto estava inativa.
  • Alta disponibilidade: Disponibilidade de apoio de ouvintes 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 através do Coordenador de Transações Distribuídas da Microsoft (MSDTC).
  • Ferramentas complementares: sqlcmd e bcp, instaladas separadamente.

Introdução

Artigo Description
Descarregar o Controlador ODBC para SQL Server Instaladores e transferências de pacotes para todas as versões de controladores suportadas, para as três plataformas.
Desenvolver aplicações em C e C++ com o driver ODBC Quais os cabeçalhos a incluir, por que ordem, que bibliotecas a ligar e como escolher entre execução assíncrona e threads.
Ligue-se e consulte uma base de dados com C++ Um exemplo completo em C++ que liga, executa uma consulta e lê resultados, para que possas confirmar a tua configuração de ponta a ponta.
Ciclo de vida do suporte Quais as versões dos drivers ainda suportadas e a data em que cada uma sai do suporte.
Principais diferenças de versão O que falha quando se passa da versão 17 para a versão 18, começando pela alteração padrão da encriptação.

Instale o controlador

Artigo Description
Requisitos do sistema, instalação e ficheiros de drivers (Windows) Versões do Windows suportadas, a linha de comandos do instalador para instalação silenciosa e onde cada ficheiro do controlador é guardado no disco.
Requisitos do sistema (Linux e macOS) Quais distribuições Linux e versões do macOS suportam cada versão do driver, além da compatibilidade com versões do SQL Server.
Instale o controlador ODBC no Linux Etapas do gestor de pacotes para Alpine, Debian, Red Hat, SUSE, Ubuntu e Azure Linux, além da instalação offline e das localizações dos ficheiros dos drivers.
Instale o driver ODBC no macOS Passos para o tap e as fórmulas do Homebrew no macOS, incluindo como instalar a versão 18, 17 ou 13.1.
Instale o gestor de drivers unixODBC (Linux e macOS) Instale ou atualize o unixODBC, o gestor de drivers que carrega o driver ODBC no Linux e macOS.

Configurar e ligar

Artigo Description
Palavras-chave e atributos de DSN e de cadeias de ligação O catálogo completo de palavras-chave de cadeia de ligação, entradas DSN e atributos SQLSetConnectAttr, com os valores aceites para cada um.
Palavras-chave de string de ligação e nomes de fontes de dados (Linux e macOS) Como definir uma DSN no Linux e macOS com odbc.ini e odbcinst.ini, além de definições de Segurança da Camada de Transporte (TLS) e Protocolo de Controlo de Transmissão (TCP) keep-alive específicas para essas plataformas.
Administrador de Fonte de Dados ODBC DSN (Windows) Configure uma fonte de dados através da interface de utilizador do Windows em vez de uma cadeia de ligação.
Agrupamento de ligações com reconhecimento do controlador (Windows) Que palavras‑chave e atributos da cadeia de ligação colocam uma ligação no seu próprio grupo, e quais implicam uma ida e volta adicional para a repor.

Autenticar e proteger

Artigo Description
Utilizar o Microsoft Entra ID com o controlador ODBC Cada Authentication valor de palavra-chave, desde identidade gerida e principal de serviço até interativo e integrado, com a configuração que cada um precisa.
Utilizar Always Encrypted com o controlador ODBC Encripte valores de colunas sensíveis antes de os enviar para a base de dados, com o resumo da API do driver e as limitações documentadas.
Classificação dos dados Leia as etiquetas de sensibilidade que o servidor atribui às colunas classificadas, para que a sua aplicação possa aplicar a sua própria política de proteção de dados.
Utilizar autenticação integrada (Linux e macOS) Configure o Kerberos para que um cliente Linux ou macOS possa ligar-se com credenciais do Windows em vez de um login do SQL Server.

Alta disponibilidade e resiliência

Artigo Description
Resiliência da ligação Como ConnectRetryCount e ConnectRetryInterval restauram uma ligação quando o servidor a interrompe quando esta está inativa, e os erros IMCxx que o controlador devolve quando a recuperação não é possível.
Alta disponibilidade e recuperação de desastres Liga-te através de um ouvinte de grupo de disponibilidade e usa MultiSubnetFailover para que o failover não fique bloqueado num timeout de subrede.
Utilizar resolução IP de rede transparente Como o Fallback legado TransparentNetworkIPResolution ordena as tentativas de ligaçã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 vetoriais Associar, enviar e recuperar o tipo vetor, incluindo a sua representação nativa em C e suporte para cópia em massa.
Usar transações XA com DTC Inscreva o SQL Server numa 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 o estado das funcionalidades, considerações sobre conjuntos de caracteres, OpenSSL e Alpine Linux.

Diagnosticar e solucionar problemas

Artigo Description
Resolução de problemas de encriptação de ligação Corrigir os erros de certificado e encriptação que a versão 18 revela porque ela encripta por defeito.
Rastreio de acesso a dados (Linux e macOS) Ativa o rastreio de condutores e captura um ficheiro de registo quando precisares de ver as chamadas que a tua aplicação realmente faz.
Problemas conhecidos (Linux e macOS) Defeitos confirmados e as suas soluções alternativas. Consulte aqui antes de submeter um pedido de suporte.
Perguntas frequentes (Linux e macOS) Respostas curtas às perguntas que surgem mais frequentemente sobre o driver no Linux e macOS.

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

Artigo Description
Notas de lançamento para Windows Novas funcionalidades, alterações de comportamento e correções em cada versão do driver do Windows.
Notas de lançamento para Linux e macOS Novas funcionalidades, alterações 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 às utilidades sqlcmd e bcp , que se instalam separadamente do driver no Linux e macOS.

Reference

Artigo Description
Controlador ODBC no Windows Um resumo, versão por versão, do que é suportado pelo controlador no Windows e um índice dos artigos específicos do Windows.
Funcionalidades do driver ODBC no Windows Qual das versões introduziu cada funcionalidade do Windows, além das alterações de comportamento associadas.

Pedir uma funcionalidade

Para solicitar uma funcionalidade, submeta uma ideia através do feedback do SQL Server.