Разработка приложений на C и C++ с помощью драйвера ODBC

Версия: 18.7.1.1
Дата: 7 сентября 2026 года

Чтобы вызвать ODBC API из C или C++, включите sql.h, sqlext.h, и sqltypes.h, затем свяжитесь с библиотекой импорта менеджера драйверов. Чтобы использовать расширения SQL Server, которые Microsoft ODBC Driver for SQL Server добавляет поверх стандарта ODBC, также включайте msodbcsql.h, и включайте его после основных заголовков ODBC.

Относится к: Microsoft ODBC Driver 18 for SQL Server на Windows, Linux и macOS. В версии 17 используется то же имя заголовочного файла, с путём установки 170 и именем библиотеки msodbcsql17.

Заголовки и библиотеки

Платформа предоставляет основные заголовки ODBC и менеджер драйверов, а не пакет драйверов. На Windows они поставляются в Windows SDK. На Linux и macOS они поставляются в пакете разработки unixODBC. SDK драйвера предоставляет только msodbcsql.h и библиотеку для импорта массового копирования.

То, что ты называешь Headers Windows Linux macOS
ODBC API sql.h, sqlext.h, sqltypes.h odbc32.lib -lodbc -lodbc
ODBC API, точки входа в Unicode Добавить sqlucode.h odbc32.lib -lodbc -lodbc
API установщика ODBC Добавить odbcinst.h odbccp32.lib -lodbcinst -lodbcinst
Расширения драйверов SQL Server Добавить msodbcsql.h Никакой дополнительной библиотеки Никакой дополнительной библиотеки Никакой дополнительной библиотеки
Функции массового копирования (bcp_*) Добавить msodbcsql.h msodbcsql18.lib -lmsodbcsql-18 -lmsodbcsql.18

Имя ссылки для массового копирования различается в зависимости от платформы, потому что имена файлов различаются. В Linux -lmsodbcsql-18 разрешается через символическую ссылку libmsodbcsql-18.so в /usr/lib, в котором компоновщик уже ищет, поэтому -L не нужен. В macOS драйвер поставляется как libmsodbcsql.18.dylib, которому соответствует -lmsodbcsql.18, но каталог библиотек Homebrew не входит в стандартный путь поиска на Apple Silicon. Добавьте -L$(brew --prefix)/lib, когда связываете функции массового копирования.

Только функции массового копирования нуждаются в собственной библиотеке драйвера. Атрибуты соединения, атрибуты операторов, атрибуты столбцов и идентификаторы типов SQL Server — это макросы и определения типов, поэтому включение msodbcsql.h для них достаточно.

API установщика является отдельной библиотекой от ODBC API. Вызов функции, такой как SQLGetPrivateProfileString без -lodbcinst , на Linux или macOS не работает во время ссылки с неопределённой ссылкой, а не во время компиляции.

Чтобы установить пакет разработки unixODBC, который предоставляет основные заголовки на Linux и macOS, см. раздел «Установить менеджер драйверов unixODBC».

Включите wchar.h до msodbcsql.h в коде на C на Linux и macOS

Версии msodbcsql.h для Linux и macOS объявляют интерфейс поставщика хранилища ключей Always Encrypted с помощью wchar_t, но не включают заголовочный файл, в котором определяется этот тип. В C++ — wchar_t это ключевое слово, поэтому единицы перевода на C++ строятся без необходимости дополнительных заголовков. В C — wchar_t это typedef, поэтому сначала нужно включить <wchar.h> в единицу перевода на C:

#include <wchar.h>

Если не включить <wchar.h>, компилятор сообщает об ошибках unknown type name 'wchar_t' внутри msodbcsql.h. Добавление директивы include в Windows безвредно, поэтому лучше добавить её в общий исходный файл, а не помещать под условную компиляцию для платформы.

Включите msodbcsql.h после основных заголовков ODBC

Всё, что msodbcsql.h определяет за пределами макросов драйвера, находится внутри #ifdef ODBCVER блока и sql.h определяет ODBCVER. Если вы включите msodbcsql.h сначала, препроцессор пропускает весь этот блок, и заголовок ничего не добавляет. Компилятор не выдаёт предупреждения.

/* Correct order. */
#ifdef _WIN32
#include <windows.h>
#endif

#include <wchar.h>
#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
#include <msodbcsql.h>

Включая msodbcsql.h до sql.h , всё внутри ODBCVER блока остаётся неопределённым. Компилятор сообщает об ошибке в месте использования, а не в директиве include:

order-wrong.c(7): error C2065: 'SQL_COPT_SS_BCP': undeclared identifier

В Windows необходимо подключить windows.h перед заголовками ODBC. Копии sqltypes.h и sql.h в Windows SDK используют типы Windows, такие как DWORD и LONG. msodbcsql.hобворачивает свои структуры SQL Server в pshpack8.h и poppack.h. Без windows.hэтого сборка проваливается внутри самих заголовков SDK.

Где установлены SDK-файлы

Platform msodbcsql.h Библиотека для массового копирования
Windows %ProgramFiles%\Microsoft SQL Server\Client SDK\ODBC\180\SDK\Include %ProgramFiles%\Microsoft SQL Server\Client SDK\ODBC\180\SDK\Lib\<architecture>\msodbcsql18.lib
Linux /opt/microsoft/msodbcsql18/include /opt/microsoft/msodbcsql18/lib64, с символьной /usr/lib/libmsodbcsql-18.so ссылкой
macOS $(brew --prefix msodbcsql18)/include/msodbcsql18 $(brew --prefix)/lib/libmsodbcsql.18.dylib

В Windows папка Lib содержит подпапку для каждой архитектуры процессора, которую установщик размещал на машине, напримерx64, , x86, или arm64. Добавьте папку Include в путь поиска включаемых файлов компилятора, а подпапку архитектуры — в путь поиска библиотек компоновщика.

В Linux разделяемый объект имеет номер версии, имя вида libmsodbcsql-18.6.so.2.1 и не содержит SONAME. Пакет устанавливает /usr/lib/libmsodbcsql-18.so, указывающий на него, что и позволяет -lmsodbcsql-18 разрешаться без параметра -L. Ссылайтесь через эту символическую ссылку, а не называйте версионный файл, чтобы обновление драйвера не сломало вашу сборку.

На macOS Homebrew устанавливается в свой собственный префикс: /opt/homebrew на компьютерах с Apple silicon и /usr/local на компьютерах с Intel. Оба префикса являются символическими ссылками в версионный каталог Cellar. Используйте brew --prefix msodbcsql18 и brew --prefix unixodbc в вашем скрипте сборки вместо того, чтобы жёстко прописывать любой из этих вариантов.

Число в пути указывает на основную версию драйвера. Версия 17 устанавливается в ...\ODBC\170\SDK\ в Windows и в /opt/microsoft/msodbcsql17/ в Linux, а её библиотека импорта — msodbcsql17.lib.

Для полного инвентаря файлов по платформам смотрите Системные требования, установка и файлы драйверов (Windows), Установка драйвера ODBC на Linux и Установка драйвера ODBC на macOS.

Проверьте свою конфигурацию сборки

Эта программа компилирует по заголовкам, ссылается на менеджер драйверов и перечисляет драйверы, которые менеджер драйверов видит. Он не подключается, поэтому отделяет проблему сборки или регистрации от сети или учетных данных.

#include <stdio.h>
#include <wchar.h>

#ifdef _WIN32
#include <windows.h>
#endif

#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
#include <msodbcsql.h>

static void PrintDiagnostics(SQLSMALLINT handleType, SQLHANDLE handle)
{
    SQLCHAR state[6];
    SQLINTEGER native;
    SQLCHAR message[SQL_MAX_MESSAGE_LENGTH];
    SQLSMALLINT length;

    for (SQLSMALLINT record = 1;
         SQL_SUCCEEDED(SQLGetDiagRec(handleType, handle, record, state, &native,
                                     message, sizeof(message), &length));
         ++record)
    {
        fprintf(stderr, "  [%s] (%ld) %s\n", state, (long)native, message);
    }
}

int main(void)
{
    SQLHENV environment = SQL_NULL_HENV;
    SQLRETURN rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &environment);

    if (!SQL_SUCCEEDED(rc))
    {
        fprintf(stderr, "SQLAllocHandle for the environment failed.\n");
        return 1;
    }

    rc = SQLSetEnvAttr(environment, SQL_ATTR_ODBC_VERSION,
                       (SQLPOINTER)SQL_OV_ODBC3_80, 0);
    if (!SQL_SUCCEEDED(rc))
    {
        fprintf(stderr, "SQLSetEnvAttr for SQL_OV_ODBC3_80 failed.\n");
        PrintDiagnostics(SQL_HANDLE_ENV, environment);
        SQLFreeHandle(SQL_HANDLE_ENV, environment);
        return 1;
    }

    printf("Driver name from msodbcsql.h: %s\n", SQLODBC_DRIVER_NAME);
    printf("Installed drivers:\n");

    SQLCHAR description[256];
    SQLSMALLINT descriptionLength = 0;
    SQLUSMALLINT direction = SQL_FETCH_FIRST;

    while (SQL_SUCCEEDED(SQLDrivers(environment, direction,
                                    description, sizeof(description), &descriptionLength,
                                    NULL, 0, NULL)))
    {
        printf("  %s\n", description);
        direction = SQL_FETCH_NEXT;
    }

    SQLFreeHandle(SQL_HANDLE_ENV, environment);
    return 0;
}

Создайте её как узкую программу для персонажей. SQLODBC_DRIVER_NAME расширяется в широкую строку, когда определён UNICODE или _UNICODE, что printf с %s не может обработать.

cl /W4 /I "%ProgramFiles%\Microsoft SQL Server\Client SDK\ODBC\180\SDK\Include" odbc-build-check.c /link odbc32.lib

На Windows, /W4 сообщает о двух предупреждениях C4201: nonstandard extension used: nameless struct/union из копии sqlext.h из Windows SDK. Эти предупреждения поступают из заголовка SDK, а не из вашего кода, и сборка проходит успешно.

Первая строка показывает имя водителя, скомпилированное в ваш бинарный файл. Остальное — это собственный список менеджера драйверов, поэтому если драйвер, который вы ожидаете увидеть, отсутствует, то это проблема регистрации, а не проблема сборки. Ваш список будет отличаться, и он включает все установленные драйверы ODBC, а не только SQL Server:

Driver name from msodbcsql.h: ODBC Driver 18 for SQL Server
Installed drivers:
  SQL Server
  ODBC Driver 17 for SQL Server
  ODBC Driver 18 for SQL Server
  Microsoft Access Driver (*.mdb, *.accdb)
  Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)
  Microsoft Access Text Driver (*.txt, *.csv)
  Microsoft Access dBASE Driver (*.dbf, *.ndx, *.mdx)

Формируйте строку подключения из SQLODBC_DRIVER_NAME, а не из строкового литерала. Макрос учитывает заголовочный файл, по которому выполнялась компиляция, поэтому при обновлении SDK имя драйвера обновляется в одном месте.

Что msodbcsql.h добавляет в API ODBC

msodbcsql.h расширяет стандартный API ODBC специфическими возможностями SQL Server. Каждое семейство занимает непрерывный числовой диапазон, отсчитываемый от базовой константы. Диапазоны не уникальны для разных семейств, поэтому функция, которой вы передаёте значение, отличает их.

Семья Базовая константа Value
Атрибуты соединения для SQLSetConnectAttr SQL_COPT_SS_BASE 1200
Атрибуты утверждений для SQLSetStmtAttr SQL_SOPT_SS_BASE 1225
Атрибуты столбцов для SQLColAttribute SQL_CA_SS_BASE 1200
Типы информации для SQLGetInfo SQL_INFO_SS_FIRST 1199
Диагностические поля для SQLGetDiagField SQL_DIAG_SS_BASE -1150
Диагностические динамические коды функций SQL_DIAG_DFC_SS_BASE -200

Заголовок также объявляет:

  • Атрибуты аутентификации, включая SQL_COPT_SS_AUTHENTICATION и SQL_COPT_SS_ACCESS_TOKEN, которые содержат настройки Microsoft Entra ID и токены доступа.
  • Идентификаторы типов SQL в диапазоне -150–-199 для SQL Server типов, которые ODBC не определяет: SQL_SS_VARIANT, SQL_SS_UDT, , SQL_SS_XMLSQL_SS_TABLE, SQL_SS_TIME2SQL_SS_TIMESTAMPOFFSET, , и SQL_SS_VECTOR. Они обозначают тип SQL, поэтому их передают там, где ODBC ожидает тип SQL, например, в качестве аргумента ParameterType у SQLBindParameter.
  • Три совпадающих типа C для буферной стороны: SQL_C_SS_TIME2, SQL_C_SS_TIMESTAMPOFFSET, и SQL_C_SS_VECTOR. Другие типы SQL Server связываются со стандартным типом ODBC C, таким как SQL_C_BINARY или SQL_C_WCHAR, поэтому у них нет SQL_C_SS_* аналога.
  • Структуры, к которым типы SQL_C_SS_* связываются: SQL_SS_TIME2_STRUCT, SQL_SS_TIMESTAMPOFFSET_STRUCT, и SQL_SS_VECTOR_STRUCT.
  • Массовое копирование прототипов и макросов, включая bcp_init, bcp_bind, bcp_sendrowbcp_batch, и bcp_done. Параметры BCP_ENCRYPT_OFF, BCP_ENCRYPT_ONи BCP_ENCRYPT_STRICT опции находятся только в заголовке Windows.

Каждая платформа поставляет свою копию msodbcsql.h, и не каждая из них объявляет одни и те же символы. Структура SQLPERF и атрибуты подключения к счётчику производительности, которые её заполняют, такие как SQL_COPT_SS_PERF_DATA и SQL_COPT_SS_PERF_QUERY, определены только в заголовочном файле Windows. Заголовки Linux и macOS не указывают их, и драйвер не собирает данные о производительности на этих платформах. См. Руководство по программированию (Linux и macOS).

Сведения о ключевых словах строки подключения, которым соответствуют эти атрибуты, см. в разделе DSN, ключевые слова и атрибуты строки подключения. Для настройки Microsoft Entra ID см. раздел «Использовать Microsoft Entra ID с драйвером ODBC». Для векторного типа см. Векторный тип данных.

Выберите между асинхронным выполнением и потоками

Некоторые функции ODBC могут выполняться как синхронно, так и асинхронно. В синхронном режиме драйвер не возвращает управление, пока сервер не ответит. В асинхронном режиме драйвер возвращается SQL_STILL_EXECUTING сразу, и приложение повторяет тот же вызов с теми же аргументами, пока не получит другой код возврата. Любой другой код возврата, включая SQL_ERROR, означает завершение операции.

Асинхронный режим имеет две формы, и вы используете одну из них. Вызовите SQLGetInfo с SQL_ASYNC_MODE, чтобы узнать, какой из них поддерживается драйвером. Возвращает SQL_AM_STATEMENT, если драйвер поддерживает управление для каждого оператора, SQL_AM_CONNECTION, если этот параметр применяется ко всему соединению, или SQL_AM_NONE, если драйвер вообще не выполняет функции асинхронно.

Форма инструкции включает асинхронный режим для одного дескриптора инструкции. Все остальные инструкции в этом соединении остаются синхронными, поэтому вы можете выполнять оба типа одновременно:

SQLSetStmtAttr(hStmt, SQL_ATTR_ASYNC_ENABLE,
               (SQLPOINTER)SQL_ASYNC_ENABLE_ON, SQL_IS_INTEGER);

Если SQL_ASYNC_MODE возвращает значение SQL_AM_CONNECTION, атрибут оператора доступен только для чтения, и этот вызов возвращает SQL_ERROR с SQLSTATE HYC00. Используйте форму соединения вместо этого.

Форма дескриптора соединения включает асинхронный режим для каждого дескриптора оператора, который вы впоследствии выделяете для этого соединения. Влияет ли это также на уже существующие дескрипторы — определяется драйвером, поэтому задайте его перед выделением каких-либо операторов:

SQLSetConnectAttr(hDbc, SQL_ATTR_ASYNC_ENABLE,
                  (SQLPOINTER)SQL_ASYNC_ENABLE_ON, SQL_IS_INTEGER);

Вызов возвращает SQL_ERROR с SQLSTATE HY010, если для оператора данного соединения функция всё ещё выполняется асинхронно. Открытый курсор сам по себе не блокирует вызов. Передача SQL_ASYNC_ENABLE_OFF переводит все инструкции в соединении обратно в синхронный режим.

Чтобы узнать, сколько асинхронных инструкций драйвер поддерживает одновременно в одном соединении, вызовите SQLGetInfo, передав SQL_MAX_ASYNC_CONCURRENT_STATEMENTS. Microsoft ODBC Driver 18 для SQL Server возвращает 1, поэтому исходите из того, что для каждого соединения возможна только одна незавершённая асинхронная операция, а сверх этого открывайте дополнительные соединения или используйте потоки. См. асинхронное исполнение (метод опроса).

Нити — это другой способ поддерживать несколько операций в полёте. ODBC требует, чтобы драйверы на многопоточных операционных системах были безопасны для потоков, поэтому поток может выполнять блокирующий вызов ODBC, пока другие потоки продолжают работать. Это позволяет избежать цикла опроса и повторяющихся вызовов функций, необходимых асинхронному режиму. Предоставьте каждому потоку собственный дескриптор оператора. Скорее всего, драйвер будет выполнять последовательно два потока, если они одновременно используют один и тот же дескриптор, поэтому при совместном использовании одного дескриптора вы теряете возможность параллельного выполнения. См. Многопоточность. Предпочитайте потоки для нового кода и измеряйте свою нагрузку перед конвертацией асинхронного кода, который уже работает.

В Windows менеджер драйверов также поддерживает метод уведомлений, который убирает цикл опросов. Вы связываете событие Win32 с дескриптором соединения или дескриптором инструкции. Функция всё равно возвращается SQL_STILL_EXECUTING сразу, и менеджер драйвера сигнализирует о событии после завершения операции. Опрос отключён в этом режиме: повторный вызов исходной функции возвращает SQL_ERROR с SQLSTATE IM017. Вызовите SQLCompleteAsync, чтобы вместо этого получить результат. Для этого нужны версии ODBC 3.81 и более поздние версии менеджера драйверов, и драйвер тоже должен это поддерживать. Позвоните SQLGetInfo с помощью SQL_ASYNC_NOTIFICATION, чтобы проверить. Получаемое вами значение зависит от версии ODBC, которую объявляет ваше приложение: при использовании Microsoft ODBC Driver 18 for SQL Server приложение, которое задаёт SQL_ATTR_ODBC_VERSION значение SQL_OV_ODBC3_80, получает SQL_ASYNC_NOTIFICATION_CAPABLE, а приложение, которое объявляет SQL_OV_ODBC3, получает SQL_ASYNC_NOTIFICATION_NOT_CAPABLE от того же драйвера. Объявите SQL_OV_ODBC3_80 перед тем, как выделять соединение. См. асинхронное выполнение (метод уведомления) и пример метода уведомления.

Отменить невыполненную операцию

SQLCancel отменяет операцию, которая всё ещё выполняется с использованием дескриптора инструкции. Вызовите его из другого потока или из цикла опроса, передав дескриптор незавершённого вызова.

Используйте SQLCancel только для этого. Чтобы прекратить чтение набора результатов, который вам больше не нужен, вместо этого вызовите SQLCloseCursor или SQLMoreResults.

Переход с sqlncli.h на msodbcsql.h

SQL Server Native Client закрыт, поэтому приложения, использующие его, должны перейти на Microsoft ODBC Driver for SQL Server. Это тот же API ODBC, поэтому большая часть работы связана с переименованием входных данных сборки и имени драйвера в строке подключения.

Нативный клиент SQL Server Microsoft драйвер ODBC 18 для SQL Server
sqlncli.h msodbcsql.h
sqlncli11.lib msodbcsql18.lib
sqlncli11.dll msodbcsql18.dll
Driver={SQL Server Native Client 11.0} Driver={ODBC Driver 18 for SQL Server}
SQLNCLI_VER SQLODBC_VER

Заголовок msodbcsql.h по-прежнему определяет макросы имён SQLNCLI_*, поэтому исходный код, который их использует, по-прежнему компилируется. Эти определения защищены с помощью #ifndef __sqlncli_h__, а это значит, что нельзя включать оба заголовочных файла в одну и ту же единицу трансляции. Уберите включение sqlncli.h .

Две вещи не переносятся:

  • Функции API метаданных распределённых запросов, возвращающие списки связанных серверов и их каталогов, не декларируются в msodbcsql.h. Они были специфичны для нативного клиента SQL Server.
  • Версия 18 по умолчанию шифрует соединения и подтверждает сертификат сервера. Native Client — нет. Строка подключения, которая работала с Native Client, может завершиться ошибкой при первом подключении, пока вы не настроите доверие к сертификату или явно не зададите Encrypt. См. раздел «Устранение неисправности шифрования соединения».

Для остальных изменений версий с 17 по версию 18 см . раздел «Основные различия в версиях».