Driver Microsoft ODBC per SQL Server

Scaricare il driver ODBC

ODBC è un'API nativa di accesso ai dati per applicazioni scritte in C e C++. Il driver Microsoft ODBC per SQL Server si collega a SQL Server, database SQL di Azure, Istanza gestita di SQL di Azure, Azure Synapse Analytics e database SQL in Microsoft Fabric. Per le versioni del database supportate da ogni release del driver, vedi compatibilità con le versioni SQL.

La tua applicazione chiama il gestore driver ODBC, che carica il driver e gli passa le chiamate ODBC. Usa il Driver Manager ODBC di Windows su Windows e unixODBC su Linux e macOS.

Altri linguaggi che possono usare ODBC sono COBOL, Perl, PHP e Python. ODBC è ampiamente utilizzato in scenari di integrazione dei dati, e i driver Microsoft per PHP per SQL Server sono basati su questo driver.

La variante ODBC di sqlcmd e l'utility bcp utilizzano questo driver, ma si installano separatamente: il pacchetto mssql-tools18 su Linux e macOS, e le utility Microsoft Command Line su Windows. La variante Go di sqlcmd non usa questo driver. Usa sqlcmd per eseguire istruzioni Transact-SQL (T-SQL), procedure di sistema e file script. Usa bcp per copiare dati in massa tra un'istanza di SQL Server e un file dati, in entrambe le direzioni.

Scegliere il punto di partenza

Baseline di produzione per Azure SQL

Usa questo programma completo in C++17 come punto di partenza per un'applicazione ospitata su Azure. Si collega, esegue SELECT 1, controlla il risultato e rilascia gli handle ODBC. Installa il driver 18 e i file di sviluppo ODBC della piattaforma prima di compilarlo. Per i prerequisiti, vedi Sviluppa applicazioni C e C++ con il driver ODBC.

Imposta ODBC_CONNECTION_STRING nell'ambiente dell'applicazione sulla tua stringa di connessione completa. Il seguente esempio utilizza un'identità gestita assegnata dal sistema. L'host deve avere quell'identità abilitata e il database deve concedergli l'accesso. Per i requisiti dell'host, le identità assegnate dall'utente e l'autenticazione per lo sviluppo locale, vedi Usa Microsoft Entra ID con il 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 richiede un endpoint che supporti Tabular Data Stream (TDS) 8.0. In caso contrario, usare Encrypt=yes;TrustServerCertificate=no. Configura un certificato di cui il client si fida e il cui nome corrisponde a quello del server. Per configurazione e verifica, vedi Risoluzione dei problemi di crittografia della connessione.

Tieni le credenziali fuori dai file sorgente e dalla cronologia della shell. Per i comandi per impostare la variabile di ambiente, vedi Configura la connessione. Su Linux e macOS, fornisci il valore come UTF-8. Salva il seguente programma come 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;
    }
}

Il programma richiede un timeout di connessione di 30 secondi per ciascuno di un massimo di quattro tentativi di connessione e un timeout di query di 10 secondi. Tra tentativi di connessione transitoria non riusciti, attende 10, 20 e 40 secondi, ciascuno con da 0 a 250 millisecondi di jitter casuale. Questi limiti non impongono una scadenza complessiva rigida per l'autenticazione. L'esempio classifica gli errori di connessione transitori selezionati; adatta la policy al tuo carico di lavoro con il catalogo degli errori transitori di Azure SQL. Non ritenta i comandi dell'applicazione né le operazioni di scrittura.

ConnectRetryCount e ConnectRetryInterval configurano la resilienza delle connessioni per le connessioni idonee che cadono mentre sono inattive. Non riprovano la connessione iniziale né rieseguono i comandi dell'applicazione. Mantieni i ritardi di recupero da inattività più brevi del timeout della tua query. Il campione registra i valori SQLSTATE e i numeri di errore nativi invece delle stringhe di connessione o dei messaggi diagnostici completi. Se hai bisogno del testo del messaggio per la risoluzione del problema, catturalo in un log diagnostico protetto.

Costruisci e esegui la baseline

Usa un ambiente di compilatore che corrisponda all'architettura del processore della tua applicazione. Su Windows, esegui i comandi in Developer PowerShell per Visual Studio. Su Linux e macOS, usa una shell con il compilatore e i file di sviluppo unixODBC disponibili.

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

Una prima connessione riuscita stampa il seguente output. Potrebbero apparire anche ulteriori registri diagnostici.

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

Cancella ODBC_CONNECTION_STRING quando finisci: usa Remove-Item Env:\ODBC_CONNECTION_STRING in PowerShell o unset ODBC_CONNECTION_STRING in Bash o Zsh.

Per i listener del gruppo di disponibilità e le impostazioni di failover, usa Alta disponibilità e disaster recovery.

Funzionalità principali

  • Multipiattaforma: La stessa API su Windows, Linux e macOS.
  • Autenticazione Microsoft Entra ID: Identità gestita, service principal e autenticazione integrata, oltre all'autenticazione interattiva su Windows. I metodi disponibili dipendono dalla configurazione dell'host e del database.
  • Crittografia rigorosa: connessioni TDS 8.0 con validazione completa dei certificati nella versione 18 e successive.
  • Always Encrypted: crittografia lato client per colonne sensibili, con supporto per provider di keystore personalizzati.
  • Resilienza della connessione: Ripristino trasparente di una connessione che si è interrotta mentre era inattiva.
  • Alta disponibilità: Supporto per listener del gruppo di disponibilità con MultiSubnetFailover.
  • Classificazione dei dati: Metadati di sensibilità per colonne classificate.
  • Tipo di dato vettoriale: Supporto nativo per il tipo vettoriale .
  • Transazioni distribuite: supporto alle transazioni XA tramite il Microsoft Distributed Transaction Coordinator (MSDTC).
  • Strumenti complementari: sqlcmd e bcp, installati separatamente.

Inizia subito

Article Description
Scarica il driver ODBC per SQL Server Download di installatori e pacchetti per ogni versione supportata del driver, su tutte e tre le piattaforme.
Sviluppare applicazioni in C e C++ con il driver ODBC Quali file di intestazione includere, in che ordine, quali librerie linkare e come scegliere tra esecuzione asincrona e thread.
Collegati e interroga un database con C++ Un campione completo di C++ che collega, esegue una query e legge i risultati, così puoi confermare la tua configurazione end-to-end.
Ciclo di vita del supporto Quali versioni di driver sono ancora supportate e la data in cui ciascuno lascia il supporto.
Differenze tra le versioni principali Cosa si rompe quando passi dalla versione 17 alla versione 18, a partire dal cambiamento predefinito della crittografia.

Installare il driver

Article Description
Requisiti di sistema, installazione e file driver (Windows) Versioni di Windows supportate, la riga di comando dell'installer per l'installazione silenziosa e dove viene salvato ciascun file del driver sul disco.
Requisiti di sistema (Linux e macOS) Quali distribuzioni Linux e versioni macOS supportano ogni versione del driver, oltre alla compatibilità con SQL Server.
Installa il driver ODBC su Linux Passaggi del gestore di pacchetti per Alpine, Debian, Red Hat, SUSE, Ubuntu e Azure Linux, oltre all'installazione offline e alle posizioni dei file dei driver.
Installa il driver ODBC su macOS Passaggi per il tap e la formula di Homebrew per macOS, incluse le istruzioni per installare la versione 18, 17 o 13.1.
Installa il driver manager unixODBC (Linux e macOS) Installa o aggiorna unixODBC, il gestore di driver che carica il driver ODBC su Linux e macOS.

Configurazione e connessione

Article Description
Parole chiave e attributi della stringa di connessione e DSN Il catalogo completo delle parole chiave della stringa di connessione, delle voci DSN e degli attributi SQLSetConnectAttr, con i valori accettati per ciascuno di essi.
Parole chiave per stringhe di connessione e nomi di sorgenti dati (Linux e macOS) Come definire un DSN su Linux e macOS con odbc.ini e odbcinst.ini, oltre alle impostazioni di Transport Layer Security (TLS) e Transmission Control Protocol (TCP) specifiche per quelle piattaforme.
Amministratore di Sorgenti Dati ODBC DSN (Windows) Configura una sorgente dati tramite l'interfaccia utente di Windows invece che tramite una stringa di connessione.
Pool di connessione consapevole del driver (Windows) Quali parole chiave e attributi della stringa di connessione fanno sì che una connessione utilizzi un pool dedicato e quali richiedono un round trip aggiuntivo per il ripristino.

Autenticazione e sicurezza

Article Description
Usa Microsoft Entra ID con il driver ODBC Ogni Authentication valore di parola chiave, dall'identità gestita e il principale del servizio a quello interattivo e integrato, con la configurazione di cui ognuno ha bisogno.
Usa Always Encrypted con il driver ODBC Crittografa i valori sensibili delle colonne prima di inviarli al database, con il riepilogo dell'API del driver e le limitazioni documentate.
Classificazione dei dati Leggi le etichette di sensibilità che il server attacca alle colonne classificate, così la tua applicazione può applicare la propria politica di protezione dei dati.
Usa l'autenticazione integrata (Linux e macOS) Configura Kerberos in modo che un client Linux o macOS possa connettersi con credenziali Windows invece che con un login SQL Server.

Disponibilità elevata e resilienza

Article Description
Resilienza della connessione Come ConnectRetryCount e ConnectRetryInterval ripristinano una connessione quando il server la interrompe durante l'inattività, e gli errori IMCxx che il driver restituisce quando il ripristino non è possibile.
Disponibilità elevata e ripristino di emergenza Connettiti tramite un listener del gruppo di disponibilità e usa MultiSubnetFailover in modo che il failover non si blocchi a causa di un timeout della subnet.
Usa una risoluzione IP di rete trasparente Come il fallback legacy TransparentNetworkIPResolution ordina i tentativi di connessione attraverso più indirizzi Internet Protocol (IP) e perché MultiSubnetFailover lo sostituisce.

Uso dei dati

Article Description
tipo di dati vettoriale Associare, inviare e recuperare il tipo vector, inclusi la sua rappresentazione nativa in C e il supporto per la copia in blocco.
Usare le transazioni XA con DTC Coinvolgi SQL Server in una transazione distribuita tramite il Microsoft Distributed Transaction Coordinator su Windows, Linux o macOS.
Linee guida di programmazione (Linux e macOS) Trova linee guida per la programmazione Linux e macOS, inclusi lo stato delle funzionalità, considerazioni sul set di caratteri, OpenSSL e Alpine Linux.

Diagnosticare e risolvere i problemi

Article Description
Risoluzione dei problemi di crittografia della connessione Correggi gli errori di certificato e crittografia che la versione 18 mostra perché viene criptata di default.
Tracciamento dell'accesso ai dati (Linux e macOS) Attiva il tracciamento dei conducenti e cattura un file di log quando hai bisogno di vedere le chiamate effettivamente fatte dalla tua applicazione.
Problemi noti (Linux e macOS) Difetti confermati e le loro soluzioni alternative. Controlla qui prima di presentare una richiesta di supporto.
Domande frequenti (Linux e macOS) Risposte brevi alle domande che emergono più spesso riguardo al driver su Linux e macOS.

Note di rilascio e correzioni di bug

Article Description
Note di rilascio per Windows Nuove funzionalità, cambiamenti comportamentali e correzioni in ogni release del driver Windows.
Note di rilascio per Linux e macOS Nuove funzionalità, cambiamenti comportamentali e correzioni in ogni release dei driver Linux e macOS.
Note di rilascio per gli strumenti SQL Server Modifiche alle utility sqlcmd e bcp , che si installano separatamente dal driver su Linux e macOS.

Reference

Article Description
Driver ODBC su Windows Un riassunto versione per versione di ciò che il driver supporta su Windows e un indice degli articoli specifici per Windows.
Caratteristiche del driver ODBC su Windows Quale versione ha introdotto ogni funzionalità di Windows, oltre ai cambiamenti comportamentali che ne sono arrivati.

Richiedere una funzionalità

Per richiedere una funzionalità, invia un'idea tramite feedback di SQL Server.