Драйвер Microsoft ODBC для SQL Server

Скачать драйвер ODBC

ODBC — это нативный интерфейс прикладного программирования (API) для доступа к данным для приложений, написанных на C и C++. Драйвер Microsoft ODBC для SQL Server подключается к SQL Server, База данных SQL Azure, Управляемый экземпляр SQL Azure, Azure Synapse Analytics и базе данных SQL в Microsoft Fabric. Для версий базы данных, поддерживаемых каждым драйвером, см. совместимость версий SQL.

Ваше приложение вызывает менеджер драйверов ODBC, который загружает драйвер и передаёт ему вызовы ODBC. Используйте Windows ODBC Driver Manager в Windows и unixODBC в Linux и macOS.

К другим языкам, которые могут использовать ODBC, относятся COBOL, Perl, PHP и Python. ODBC широко используется в сценариях интеграции данных, и драйверы Microsoft для PHP для SQL Server построены на этом драйвере.

ODBC-версия sqlcmd и утилита bcp используют этот драйвер, но устанавливаются отдельно: пакет mssql-tools18 на Linux и macOS, а утилиты командной строки Microsoft — в Windows. Вариант sqlcmd для Go не использует этот драйвер. Используйте sqlcmd для запуска операторов Transact-SQL (T-SQL), системных процедур и скриптов. Используйте bcp для массового копирования данных между экземпляром SQL Server и файлом данных, в любом направлении.

Выберите начальную точку

Производственные базовые показатели для Azure SQL

Используйте эту полную программу на C++17 как отправную точку для приложения, размещённого на Azure. Подключается, запускает SELECT 1, проверяет результат и освобождает ODBC-дескрипторы. Установите драйвер 18 и файлы разработки ODBC для платформы перед сборкой. Для предварительных требований см. «Разработка приложений C и C++ с драйвером ODBC».

Установите ODBC_CONNECTION_STRING в среде приложения как полную строку подключения. В следующем примере используется управляемое удостоверение, назначенное системой. На хосте должна быть включена эта идентичность, и база данных должна предоставить ей доступ. Для требований к хосту, назначаемым пользователем удостоверениям и аутентификации для локальной разработки см. раздел «Использование Microsoft Entra ID с драйвером 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 требует конечную точку, поддерживающую Tabular Data Stream (TDS) 8.0. В противном случае используйте Encrypt=yes;TrustServerCertificate=no. Настройте сертификат, которому клиент доверяет и чьё имя совпадает с именем сервера. Для настройки и проверки см. раздел Устранение неполадок шифрования соединения.

Держите учетные данные вне исходных файлов и истории shell. Команды для установки переменной среды см. в разделе «Настройка подключения». На Linux и macOS укажите его значение в кодировке UTF-8. Сохраните следующую программу как 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;
    }
}

Программа запрашивает 30-секундный тайм-аут соединения для каждой из не более четырёх попыток подключения и 10-секундный тайм-аут для запроса. Между неудачными попытками подключения после кратковременных сбоев он ждёт 10, 20 и 40 секунд, каждая с 0–250 миллисекундами случайного джиттера. Эти ограничения не устанавливают жёсткого общего предельного срока для аутентификации. В примере классифицируются выбранные временные ошибки подключения; адаптируйте политику к вашей рабочей нагрузке с помощью каталога временных ошибок Azure SQL. Он не повторяет команды приложения и операции записи.

ConnectRetryCount и ConnectRetryInterval настраивают устойчивость соединения для подходящих соединений, которые отключаются во время простоя. Они не повторяют начальное подключение и не повторно выполняют команды приложения. Держите задержки восстановления после простоя короче, чем тайм-аут вашего запроса. В примере фиксируются значения SQLSTATE и нативные номера ошибок вместо строк соединения или полных диагностических сообщений. Если вам нужен текст сообщения для устранения неполадок, зафиксируйте его в защищённом диагностическом журнале.

Соберите и запустите базовую версию

Используйте среду компиляции, соответствующую архитектуре процессора вашего приложения. В Windows выполните команды в Developer PowerShell for Visual Studio. В Linux и macOS используйте командную оболочку, в которой доступны компилятор и файлы разработки unixODBC.

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

Успешное первое соединение выводит следующий результат. Также могут появиться дополнительные диагностические записи.

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

Очищайте ODBC_CONNECTION_STRING , когда закончите: используйте Remove-Item Env:\ODBC_CONNECTION_STRING в PowerShell, или unset ODBC_CONNECTION_STRING в Bash или Zsh.

Для прослушивателей групп доступности и параметров отработки отказа используйте высокую доступность и аварийное восстановление.

Ключевые особенности

  • Кроссплатформенность: тот же API на Windows, Linux и macOS.
  • Аутентификация Microsoft Entra ID: управляемая идентификация, субъект-служба и интегрированная аутентификация, а также интерактивная аутентификация в Windows. Доступные методы зависят от конфигурации хоста и базы данных.
  • Строгое шифрование: подключения TDS 8.0 с полной валидацией сертификата в версиях 18 и позднее.
  • Always Encrypted: клиентское шифрование для конфиденциальных столбцов с поддержкой пользовательских поставщиков хранилищ ключей.
  • Устойчивость соединения: Прозрачное восстановление соединения, которое оторвалось во время простоя.
  • Высокая доступность: поддержка прослушивателя группы доступности с MultiSubnetFailover.
  • Классификация данных: Метаданные чувствительности для классифицированных столбцов.
  • Векторный тип данных: нативная поддержка векторного типа.
  • Распределённые транзакции: поддержка транзакций XA через координатор распределенных транзакций (Майкрософт) (MSDTC).
  • Сопутствующие инструменты: sqlcmd и bcp, устанавливаются отдельно.

Начало работы

Статья Description
Скачайте драйвер ODBC для SQL Server Установщики и пакеты для загрузки для всех поддерживаемых версий драйверов на всех трёх платформах.
Разработка приложений на C и C++ с помощью драйвера ODBC Какие заголовки включать, в каком порядке, какие библиотеки связывать и как выбирать между асинхронным выполнением и потоками.
Подключитесь к базе данных и отправьте к ней запрос на C++ Полный сэмпл на C++, который подключается, выполняет запрос и читает результаты, чтобы вы могли подтвердить свою настройку от конца до конца.
Жизненный цикл поддержки Какие версии драйверов всё ещё поддерживаются, и дата прекращения поддержки каждой из них.
Различия между мажорными версиями Что ломается при переходе с версии 17 на версию 18, начиная с изменения по умолчанию шифрования?

Установка драйвера

Статья Description
Системные требования, установка и файлы драйверов (Windows) Поддерживаемые версии Windows, командная строка установщика для тихого развертывания и место, где каждый файл драйвера попадает на диск.
Системные требования (Linux и macOS) Какие дистрибутивы Linux и релизы macOS поддерживают каждая версия драйверов, плюс совместимость версий SQL Server.
Установите драйвер ODBC на Linux Шаги менеджера пакетов для Alpine, Debian, Red Hat, SUSE, Ubuntu и Azure Linux, а также офлайн-установка и расположение файлов драйверов.
Установите драйвер ODBC на macOS Шаги для tap-репозитория и формулы Homebrew в macOS, включая инструкции по установке версий 18, 17 или 13.1.
Установите менеджер драйверов unixODBC (Linux и macOS) Установите или обновите unixODBC — менеджер драйверов, который загружает драйвер ODBC на Linux и macOS.

Настройка и подключение

Статья Description
Ключевые слова и атрибуты DSN и строки подключения Полный каталог ключевых слов строк подключения, записей DSN и атрибутов SQLSetConnectAttr с допустимыми значениями для каждого из них.
Ключевые слова для строк соединения и имена источников данных (Linux и macOS) Как odbc.ini и odbcinst.ini определяют DSN в Linux и macOS, а также настройки безопасности транспортного уровня (TLS) и поддержания соединения протокола управления передачей (TCP), специфичные для этих платформ.
Администратор источников данных ODBC DSN (Windows) Настройте источник данных через пользовательский интерфейс Windows вместо строка подключения.
Пул соединений с учётом драйвера (Windows) Какие ключевые слова и атрибуты строка подключения помещают соединение в отдельный пул, а какие требуют дополнительного сброса.

Аутентифицировать и защитить

Статья Description
Используйте Microsoft Entra ID с драйвером ODBC Каждое Authentication значение ключевого слова — от управляемой идентичности и принципа сервиса до интерактивных и интегрированных, с необходимой каждой системой.
Используйте Always Encrypted с драйвером ODBC Зашифруйте чувствительные значения столбцов перед отправкой в базу данных, учитывая описание API драйвера и задокументированные ограничения.
Классификация данных Считывать метки конфиденциальности, которые сервер назначает классифицированным столбцам, чтобы приложение могло применять собственную политику защиты данных.
Используйте интегрированную аутентификацию (Linux и macOS) Настройте Kerberos так, чтобы клиент Linux или macOS мог подключаться к учетным данным Windows вместо входа через SQL Server.

Высокий уровень доступности и устойчивость

Статья Description
Устойчивость подключения Как ConnectRetryCount и ConnectRetryInterval восстанавливают соединение, когда сервер разрывает его во время простоя, и какие IMCxx ошибки возвращает драйвер, когда восстановление невозможно.
Высокий уровень доступности и аварийное восстановление Подключайтесь через прослушиватель группы доступности и используйте MultiSubnetFailover, чтобы переключение при отказе не зависало из-за тайм-аута подсети.
Используйте прозрачное разрешение сетевых IP-адресов Как устаревший TransparentNetworkIPResolution запасной вариант упорядочивает попытки подключения по нескольким IP-адресам Интернет-протокола и почему MultiSubnetFailover заменяет его.

Работа с данными

Статья Description
Векторный тип данных Привязать, отправить и получить тип vector, включая его нативное представление на C и поддержку пакетного копирования.
Используйте транзакции XA с DTC Зарегистрируйте SQL Server в распределённой транзакции через координатор распределенных транзакций (Майкрософт) на Windows, Linux или macOS.
Руководство по программированию (Linux и macOS) Найдите рекомендации по программированию Linux и macOS, включая статус функций, параметры набора символов, OpenSSL и Alpine Linux.

Диагностика и устранение неполадок

Статья Description
Устранение неполадок шифрования соединения Исправьте ошибки сертификата и шифрования, которые появляются в версии 18, потому что она шифрует по умолчанию.
Трассировка доступа к данным (Linux и macOS) Включите трассировку драйверов и зафиксируйте файл журнала, когда вам нужно увидеть, какие вызовы действительно совершает ваше приложение.
Известные проблемы (Linux и macOS) Подтверждённые дефекты и их обходные пути. Проверьте здесь, прежде чем подавать заявление в поддержку.
Часто задаваемые вопросы (Linux и macOS) Краткие ответы на вопросы, которые чаще всего возникают о драйвере на Linux и macOS.

Примечания к релизу и исправления ошибок

Статья Description
Заметки к релизу для Windows Новые функции, изменения поведения и исправления в каждом выпуске драйверов Windows.
Заметки к релизу для Linux и macOS Новые функции, изменения поведения и исправления в каждом выпуске драйверов Linux и macOS.
Заметки к релизу инструментов SQL Server Изменения в утилитах sqlcmd и bcp , которые устанавливаются отдельно от драйвера на Linux и macOS.

Ссылки

Статья Description
Драйвер ODBC на Windows Обзор версий по версиям того, что поддерживает драйвер в Windows, и индекс статей, специфичных для Windows.
Особенности драйвера ODBC в Windows В каком релизе появились все функции Windows, а также изменения в поведении, связанные с ней.

Запрашивание функции

Чтобы запросить новую функцию, отправьте предложение через отзывы о SQL Server.