Desenvolver aplicações em C e C++ com o driver ODBC

Versão: 18.7.1.1
Data: 7 de setembro de 2026

Para chamar a API ODBC a partir de C ou C++, inclua sql.h, sqlext.h, e sqltypes.h, então faça o link contra a biblioteca de importação do gerenciador de drivers. Para usar as extensões do SQL Server que o Microsoft ODBC Driver for SQL Server adiciona ao padrão ODBC, inclua também msodbcsql.h e inclua-o após os arquivos de cabeçalho principais do ODBC.

Aplica-se a: Microsoft ODBC Driver 18 para SQL Server em Windows, Linux e macOS. A versão 17 usa o mesmo nome de cabeçalho com um 170 caminho de instalação e um nome de msodbcsql17 biblioteca.

Cabeçalhos e bibliotecas

A plataforma fornece os cabeçalhos ODBC principais e o gerenciador de drivers, não o pacote de drivers. No Windows, eles são fornecidos no SDK do Windows. No Linux e macOS, eles são incluídos no pacote de desenvolvimento unixODBC. O SDK do driver fornece apenas msodbcsql.h e a biblioteca de importação para cópia em massa.

O que você está chamando Headers Windows Linux macOS
API do ODBC sql.h, sqlext.h, sqltypes.h odbc32.lib -lodbc -lodbc
API ODBC, pontos de entrada Unicode Adicionar sqlucode.h odbc32.lib -lodbc -lodbc
API de instalador ODBC Adicionar odbcinst.h odbccp32.lib -lodbcinst -lodbcinst
Extensões de drivers do SQL Server Adicionar msodbcsql.h Sem biblioteca extra Sem biblioteca extra Sem biblioteca extra
Funções de cópia em massa (bcp_*) Adicionar msodbcsql.h msodbcsql18.lib -lmsodbcsql-18 -lmsodbcsql.18

O nome do link de cópia em massa varia conforme a plataforma porque os nomes dos arquivos são diferentes. No Linux, -lmsodbcsql-18 é resolvido por meio de um link simbólico libmsodbcsql-18.so em /usr/lib, que o ligador já procura, portanto você não precisa de -L. No macOS, o driver vem como libmsodbcsql.18.dylib, ao qual -lmsodbcsql.18 corresponde, mas o diretório de bibliotecas do Homebrew não está no caminho de pesquisa padrão em Macs com Apple silicon. Adicione -L$(brew --prefix)/lib quando você vincula as funções de cópia em massa.

Apenas as funções de cópia em massa precisam da biblioteca do próprio driver. Atributos de conexão, atributos de instrução, atributos de coluna e identificadores de tipo SQL Server são macros e definições de tipo, então incluir msodbcsql.h é suficiente para eles.

A API do instalador é uma biblioteca separada da API ODBC. Chamar uma função, como SQLGetPrivateProfileString sem -lodbcinst no Linux ou macOS, falha no tempo do link com uma referência indefinida, não no momento da compilação.

Para instalar o pacote de desenvolvimento unixODBC que fornece os cabeçalhos principais no Linux e macOS, veja Instalar o gerenciador de drivers unixODBC.

Inclua wchar.h antes do msodbcsql.h no código C no Linux e macOS

As versões do Linux e do macOS de msodbcsql.h declaram a interface do provedor de keystore Always Encrypted usando wchar_t, mas não incluem um arquivo de cabeçalho que defina esse tipo de dado. Em C++, wchar_t é uma palavra-chave, então as unidades de tradução em C++ são construídas sem precisar de cabeçalhos extras. Em C, wchar_t é um typedef, então você precisa incluir <wchar.h> primeiro em uma unidade de tradução em C:

#include <wchar.h>

Se você não incluir <wchar.h>, o compilador relata erros unknown type name 'wchar_t' de dentro de msodbcsql.h. Adicionar a inclusão é inofensiva no Windows, então adicione-a à fonte compartilhada em vez de colocá-la atrás de um protetor de plataforma.

Incluir msodbcsql.h após os cabeçalhos ODBC principais

Tudo o que msodbcsql.h define além das macros de nome do driver está dentro de um bloco #ifdef ODBCVER, e sql.h é quem define ODBCVER. Se você incluir msodbcsql.h primeiro, o pré-processador pula esse bloco inteiro e o cabeçalho não contribui em nada. O compilador não emite nenhum aviso.

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

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

Incluir msodbcsql.h antes de sql.h deixa tudo dentro do bloco ODBCVER indefinido. O compilador relata o erro no ponto de uso, não na diretiva include:

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

No Windows, você deve incluir windows.h antes dos cabeçalhos ODBC. As cópias do SDK do Windows de sqltypes.h e sql.h usam tipos do Windows como DWORD e LONG. msodbcsql.henvolve suas estruturas do SQL Server em pshpack8.h e poppack.h. Sem windows.h, a build falha dentro dos próprios cabeçalhos do SDK.

Onde os arquivos SDK são instalados

Platform msodbcsql.h Biblioteca de cópias em massa
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, com um /usr/lib/libmsodbcsql-18.so link simbólico
macOS $(brew --prefix msodbcsql18)/include/msodbcsql18 $(brew --prefix)/lib/libmsodbcsql.18.dylib

No Windows, a Lib pasta contém uma subpasta para cada arquitetura de processador que o instalador colocou na máquina, como x64, x86, ou arm64. Adicione a Include pasta ao caminho include do compilador e a subpasta de arquitetura ao caminho da biblioteca do linker.

No Linux, o objeto compartilhado é versionado, nomeado como libmsodbcsql-18.6.so.2.1, e não carrega .SONAME O pacote instala /usr/lib/libmsodbcsql-18.so apontando para ele, o que faz com que -lmsodbcsql-18 seja resolvido sem uma opção -L. Faça o link por esse symlink em vez de nomear o arquivo versionado, assim uma atualização do driver não quebra sua build.

No macOS, o Homebrew é instalado em um prefixo próprio, que corresponde a /opt/homebrew em Apple Silicon e a /usr/local em Intel. Ambos os prefixos são links simbólicos para o diretório versionado do Cellar. Use brew --prefix msodbcsql18 e brew --prefix unixodbc no seu script de build em vez de codificar fixamente qualquer um dos dois.

O número no caminho acompanha a versão principal do driver. A versão 17 é instalada em ...\ODBC\170\SDK\ no Windows e em /opt/microsoft/msodbcsql17/ no Linux, e sua biblioteca de importação é msodbcsql17.lib.

Para o inventário completo de arquivos por plataforma, veja Requisitos do sistema, arquivos de instalação e drivers (Windows),Instale o driver ODBC no Linux e Instale o driver ODBC no macOS.

Verifique sua configuração de build

Este programa compila com base nos cabeçalhos, faz links com o gerenciador de drivers e lista os drivers que o gerenciador pode ver. Não há conexão, então isso permite diferenciar um problema de compilação ou de registro de um problema de rede ou de credenciais.

#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;
}

Compile-o como um programa de caracteres estreitos. SQLODBC_DRIVER_NAME se expande para uma cadeia de caracteres ampla quando UNICODE ou _UNICODE estiver definido, que printf com %s não pode aceitar.

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

No Windows, /W4 reporta dois C4201: nonstandard extension used: nameless struct/union avisos da cópia do SDK do Windows de sqlext.h. Esses avisos vêm do cabeçalho do SDK, não do seu código, e a compilação é bem-sucedida.

A primeira linha indica o nome do driver compilado em seu binário. O restante é a própria lista do gerenciador de drivers, portanto, se um driver que você espera ver não aparece, isso é um problema de registro, não de compilação. Sua lista vai variar, e inclui todos os drivers ODBC instalados, não apenas os do 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)

Construa a cadeia de conexão a partir de SQLODBC_DRIVER_NAME em vez de um literal de cadeia de caracteres. A macro rastreia o arquivo de cabeçalho usado na compilação, de modo que a atualização do SDK atualize o nome do driver em um só lugar.

O que msodbcsql.h adiciona à API ODBC

msodbcsql.hestende a API padrão do ODBC com especificidades do SQL Server. Cada família ocupa um intervalo numérico contíguo contado a partir de uma constante base. Os intervalos não são únicos entre famílias, então a função para a qual você passa o valor é o que os diferencia.

Família Constante base Value
Atributos de conexão para SQLSetConnectAttr SQL_COPT_SS_BASE 1200
Atributos de declaração para SQLSetStmtAttr SQL_SOPT_SS_BASE 1225
Atributos de coluna para SQLColAttribute SQL_CA_SS_BASE 1200
Tipos de informação para SQLGetInfo SQL_INFO_SS_FIRST 1199
Campos diagnósticos para SQLGetDiagField SQL_DIAG_SS_BASE -1150
Códigos de função dinâmica de diagnóstico SQL_DIAG_DFC_SS_BASE -200

O cabeçalho também declara:

  • Atributos de autenticação, incluindo SQL_COPT_SS_AUTHENTICATION e SQL_COPT_SS_ACCESS_TOKEN, que carregam configurações do Microsoft Entra ID e tokens de acesso.
  • Identificadores de tipo SQL no intervalo -150 a -199 para SQL Server tipos que o ODBC não define: SQL_SS_VARIANT, SQL_SS_UDT, SQL_SS_XML, SQL_SS_TABLE, SQL_SS_TIME2, SQL_SS_TIMESTAMPOFFSET, , e SQL_SS_VECTOR. Eles designam um tipo SQL, então você os fornece onde o ODBC espera um tipo SQL, como o argumento ParameterType de SQLBindParameter.
  • Três tipos C correspondentes para o lado do buffer: SQL_C_SS_TIME2, SQL_C_SS_TIMESTAMPOFFSET, e SQL_C_SS_VECTOR. Os outros tipos do SQL Server são vinculados a um tipo C padrão do ODBC, como SQL_C_BINARY ou SQL_C_WCHAR, portanto não têm um equivalente SQL_C_SS_*.
  • As estruturas às quais os tipos SQL_C_SS_* se vinculam: SQL_SS_TIME2_STRUCT, SQL_SS_TIMESTAMPOFFSET_STRUCT e SQL_SS_VECTOR_STRUCT.
  • Protótipos e macros de cópia em massa, incluindo bcp_init, bcp_bind, bcp_sendrow, bcp_batch, e bcp_done. As opções BCP_ENCRYPT_OFF, BCP_ENCRYPT_ON e BCP_ENCRYPT_STRICT estão apenas no arquivo de cabeçalho do Windows.

Cada plataforma envia sua própria cópia de msodbcsql.h, e nem todas declaram os mesmos símbolos. A SQLPERF estrutura e os atributos de conexão de desempenho que a preenchem, como SQL_COPT_SS_PERF_DATA e SQL_COPT_SS_PERF_QUERY, estão apenas no cabeçalho do Windows. Os cabeçalhos do Linux e macOS não os declaram, e o driver não coleta dados de desempenho nessas plataformas. Veja Diretrizes de Programação (Linux e macOS).

Para ver as palavras-chave da cadeia de conexão às quais esses atributos correspondem, consulte DSN, palavras-chave e atributos da cadeia de conexão. Para a configuração do Microsoft Entra ID, veja Usar o Microsoft Entra ID com o driver ODBC. Para o tipo vetorial , veja Tipo de dado vetorial.

Escolha entre execução assíncrona e threads

Algumas funções ODBC podem rodar de forma síncrona ou assíncrona. No modo síncrono, o driver não retorna ao controle até que o servidor atenda. No modo assíncrono, o driver retorna SQL_STILL_EXECUTING imediatamente, e o aplicativo repete a mesma chamada com os mesmos argumentos até receber um código de retorno diferente. Qualquer outro código de retorno, incluindo SQL_ERROR, significa que a operação foi concluída.

O modo assíncrono tem duas formas, e você usa uma delas. Chame SQLGetInfo com SQL_ASYNC_MODE para descobrir qual deles o driver suporta. Ele retorna SQL_AM_STATEMENT se o driver suporta controle por sentença, SQL_AM_CONNECTION se a configuração se aplica a toda a conexão, ou SQL_AM_NONE se o driver não executa funções assíncronas de forma alguma.

A forma da instrução ativa o modo assíncrono para um identificador de instrução. Todas as outras instruções na conexão permanecem síncronas, então você pode rodar os dois tipos ao mesmo tempo:

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

Se SQL_ASYNC_MODE retornar SQL_AM_CONNECTION, o atributo de instrução é somente leitura e esta chamada retorna SQL_ERROR com SQLSTATE HYC00. Use o formulário de conexão em vez disso.

O formulário de conexão ativa o modo assíncrono para cada handle de instrução que você aloca nessa conexão depois. Se isso também afeta handles que já existem é definido pelo driver, então defina antes de alocar qualquer instrução:

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

A chamada retorna SQL_ERROR com SQLSTATE HY010 se uma função ainda estiver sendo executada de forma assíncrona em uma instrução associada a essa conexão. Um cursor aberto sozinho não bloqueia a chamada. Ao passar SQL_ASYNC_ENABLE_OFF, todos os comandos da conexão voltam ao modo síncrono.

Para descobrir quantas instruções assíncronas o driver suporta simultaneamente em uma única conexão, chame SQLGetInfo com SQL_MAX_ASYNC_CONCURRENT_STATEMENTS. O Driver ODBC 18 da Microsoft para SQL Server retorna o valor 1, então considere uma operação assíncrona pendente por conexão e abra conexões adicionais ou use threads para ultrapassar esse limite. Veja Execução assíncrona (método de polling).

Threads são a outra forma de manter várias operações em funcionamento. O ODBC exige que os drivers em sistemas operacionais multitarefa sejam seguros para threads, para que uma thread possa fazer uma chamada ODBC com bloqueio enquanto outras threads continuam em execução. Isso evita o loop de sondagem e as chamadas repetidas de função que o modo assíncrono precisa. Dê a cada thread seu próprio handle de comando. É provável que um driver serialize duas threads que usem o mesmo identificador simultaneamente; portanto, compartilhar um deles faz você perder a concorrência. Consulte Multithreading. Prefira threads para código novo e meça sua própria carga de trabalho antes de converter código assíncrono que já funciona.

No Windows, o gerenciador de drivers também suporta o método de notificação, que remove o loop de sondeamento. Você associa um evento Win32 ao handle de conexão ou ao handle de instrução. A função ainda retorna SQL_STILL_EXECUTING imediatamente, e o gerenciador do motorista sinaliza o evento quando a operação termina. A sondagem fica desabilitada nesse modo: chamar a função original novamente retorna SQL_ERROR com SQLSTATE IM017. Chame SQLCompleteAsync para obter o resultado em vez disso. Isso precisa do gerenciador de drivers versão ODBC 3.81 e versões posteriores, e o driver também precisa suportá-lo. Ligue para SQLGetInfo com SQL_ASYNC_NOTIFICATION para verificar. O valor que você recebe de volta depende da versão do ODBC que seu aplicativo declara: com o Microsoft ODBC Driver 18 para SQL Server, um aplicativo que define SQL_ATTR_ODBC_VERSION como SQL_ASYNC_NOTIFICATION_CAPABLE recebe SQL_OV_ODBC3_80, e um que declara SQL_OV_ODBC3 recebe SQL_ASYNC_NOTIFICATION_NOT_CAPABLE desse mesmo driver. Declare SQL_OV_ODBC3_80 antes de alocar a conexão. Veja Execução assíncrona (método de notificação) e o exemplo do método de notificação.

Cancelar uma operação pendente

SQLCancel cancela uma operação que ainda está em execução em um identificador de instrução. Chame-a de outra thread ou do loop de sondagem, passando o identificador da chamada em andamento.

Use SQLCancel apenas para isso. Para abandonar um conjunto de resultados que você não deseja mais ler, chame SQLCloseCursor ou SQLMoreResults em vez disso.

Migrar de sqlncli.h para msodbcsql.h

O SQL Server Native Client está aposentado, então as aplicações que o utilizam devem migrar para o Microsoft ODBC Driver for SQL Server. A API é a mesma API ODBC, então a maior parte do trabalho envolve renomear entradas de build e o nome do driver na cadeia de conexão.

SQL Server Cliente Nativo Microsoft ODBC Driver 18 para 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

O cabeçalho msodbcsql.h ainda define as macros de nome SQLNCLI_*, então o código-fonte que as utiliza continua compilando. Essas definições são protegidas por #ifndef __sqlncli_h__, o que significa que você não pode incluir ambos os cabeçalhos na mesma unidade de tradução. Remova a inclusão sqlncli.h.

Duas coisas não se mantém:

  • As funções da API de metadados de consulta distribuídas que retornam listas de servidores vinculados e seus catálogos não são declaradas em msodbcsql.h. Eles eram específicos para o SQL Server Native Client.
  • A versão 18 criptografa as conexões por padrão e valida o certificado do servidor. O Native Client não fez. Uma cadeia de conexão que funcionava com Native Client pode falhar na primeira conexão até que você conserte a confiança do certificado ou configure Encrypt explicitamente. Veja Solução de problemas de criptografia de conexão.

Para o restante das mudanças da versão 17 à versão 18, veja Diferenças principais na versão.