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, depois ligue à biblioteca de importação do gestor de drivers. Para utilizar as extensões do SQL Server que o Microsoft ODBC Driver for SQL Server adiciona além das da norma ODBC, inclua também msodbcsql.h e faça-o após os ficheiros 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 gestor de drivers, não o pacote de drivers. No Windows, são fornecidos com o SDK do Windows. No Linux e macOS, são incluídos no pacote de desenvolvimento unixODBC. O SDK do controlador fornece apenas msodbcsql.h e a biblioteca de importação de cópia em massa.

Aquilo a que estás a chamar Headers Windows Linux macOS
ODBC API 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 consoante a plataforma porque os nomes dos ficheiros diferem. No Linux, -lmsodbcsql-18 é resolvido através de uma ligação simbólica libmsodbcsql-18.so em /usr/lib, que o editor de ligações já pesquisa, pelo que não é necessário -L. Em macOS, o driver é disponibilizado como libmsodbcsql.18.dylib, ao qual -lmsodbcsql.18 corresponde, mas o diretório de bibliotecas do Homebrew não está no caminho de pesquisa predefinido nos sistemas Apple silicon. Adiciona -L$(brew --prefix)/lib quando ligas as funções de cópia em massa.

Só as funções de cópia em massa precisam da própria biblioteca do 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 tipos, por isso incluir msodbcsql.h é suficiente para eles.

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

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

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

As versões de Linux e macOS de msodbcsql.h declaram a interface do fornecedor do arquivo de chaves Always Encrypted através de wchar_t, mas não incluem um cabeçalho que defina esse tipo. Em C++, wchar_t é uma palavra-chave, por isso as unidades de tradução C++ constroem-se sem necessidade de cabeçalhos adicionais. Em C, wchar_t é um typedef, por isso tens de incluir <wchar.h> primeiro numa unidade de tradução C:

#include <wchar.h>

Se não incluir <wchar.h>, o compilador gera erros unknown type name 'wchar_t' no interior de msodbcsql.h. Adicionar a inclusão é inofensiva no Windows, por isso adiciona-a à fonte partilhada em vez de a colocar atrás de um protetor de plataforma.

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

Tudo o que msodbcsql.h define para além das macros de nome do controlador está dentro de um bloco #ifdef ODBCVER, e sql.h é aquilo que define ODBCVER. Se incluires msodbcsql.h primeiro, o pré-processador salta esse bloco inteiro e o cabeçalho não contribui para 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 assinala o erro no ponto de utilização, não na diretiva include:

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

No Windows, deve incluir windows.h antes dos cabeçalhos ODBC. As cópias de sqltypes.h e sql.h no SDK do Windows utilizam tipos do Windows, como DWORD e LONG. msodbcsql.h encapsula as 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 ficheiros SDK são instalados

Plataforma 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 uma /usr/lib/libmsodbcsql-18.so ligação simbólica
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 partilhado tem versão, tem um nome como libmsodbcsql-18.6.so.2.1 e não inclui 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. Liga através desse symlink em vez de nomear o ficheiro versionado, para que uma atualização do driver não estrague a tua build.

No macOS, o Homebrew é instalado no seu próprio prefixo, que é /opt/homebrew em Apple silicon e /usr/local em Intel. Ambos os prefixos são ligações simbólicas para o diretório versionado Cellar. Usa brew --prefix msodbcsql18 e brew --prefix unixodbc no teu script de build em vez de codificar diretamente qualquer um deles.

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

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

Verifica a configuração da tua build

Este programa é compilado com base nos ficheiros de cabeçalho, é ligado ao gestor de controladores e lista os controladores que o gestor de controladores consegue ver. Não estabelece ligação, por isso permite distinguir um problema de compilação ou de registo 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 expande para uma cadeia de carateres larga quando UNICODE ou _UNICODE estiverem definidos, que printf com %s não consegue aceitar.

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

No sistema Windows, /W4 comunica duas C4201: nonstandard extension used: nameless struct/union advertências na cópia do sqlext.h incluída no SDK do Windows. Estes avisos vêm do cabeçalho do SDK, não do teu código, e a compilação tem sucesso.

A primeira linha indica o nome do driver compilado no seu binário. O resto é a própria lista do gestor de controladores, por isso, se um controlador que espera ver não aparece, trata-se de um problema de registo, não de compilação. A sua lista será diferente, 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)

Constrói a cadeia de ligação a partir de SQLODBC_DRIVER_NAME em vez de uma cadeia literal. A macro acompanha o cabeçalho contra o qual compilaste, por isso atualizar o SDK atualiza o nome do driver num só local.

O que o 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, por isso a função a que passas o valor é o que os distingue.

Família Constante base Value
Atributos de ligação para SQLSetConnectAttr SQL_COPT_SS_BASE 1200
Atributos da 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 transportam as definições do Microsoft Entra ID e os 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. Estas designam um tipo SQL, pelo que deve passá-las 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 correspondem a um tipo C ODBC padrão, como SQL_C_BINARY ou SQL_C_WCHAR, pelo que não têm equivalente em SQL_C_SS_*.
  • As estruturas a que os tipos SQL_C_SS_* se associam: 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 existem apenas no cabeçalho do Windows.

Cada plataforma envia a sua própria cópia de msodbcsql.h, e nem todas declaram os mesmos símbolos. A SQLPERF estrutura e os atributos de ligaçã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 Linux e macOS não os declaram, e o driver não recolhe dados de desempenho nessas plataformas. Ver Diretrizes de Programação (Linux e macOS).

Para conhecer as palavras-chave da cadeia de ligação a que estes atributos correspondem, consulte DSN e palavras-chave e atributos da cadeia de ligaçã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 dados vetorial.

Escolha entre execução assíncrona e threads

Algumas funções ODBC podem correr de forma síncrona ou assíncrona. Em modo síncrono, o condutor não devolve o controlo até que o servidor atenda. Em modo assíncrono, o driver retorna SQL_STILL_EXECUTING imediatamente, e a aplicação repete a mesma chamada com os mesmos argumentos até obter um código de retorno diferente. Qualquer outro código de retorno, incluindo SQL_ERROR, significa que a operação terminou.

O modo assíncrono tem duas formas, e usas uma delas. Chame SQLGetInfo com SQL_ASYNC_MODE para descobrir qual deles o controlador suporta. Ele retorna SQL_AM_STATEMENT se o driver suportar controlo por instrução, SQL_AM_CONNECTION se a definição se aplicar a toda a ligação, ou SQL_AM_NONE se o driver não executar funções de forma assíncrona.

O formulário de instrução ativa o modo assíncrono para um identificador de instrução. Todas as outras instruções na ligação continuam a ser síncronas, por isso pode executar os dois tipos ao mesmo tempo:

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

Se SQL_ASYNC_MODE devolveu SQL_AM_CONNECTION, o atributo da instrução é só de leitura e esta chamada devolve SQL_ERROR com SQLSTATE HYC00. Utilize o formulário de contacto em vez disso.

O formulário de ligação ativa o modo assíncrono para cada handle de instrução que alocar nessa ligação depois. Se também afeta os handles que já existem é definido pelo driver, por isso defina antes de alocar quaisquer instruções:

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 a ser executada assíncrona numa instrução para essa ligação. Um cursor aberto sozinho não bloqueia a chamada. Ao passar SQL_ASYNC_ENABLE_OFF, todas as instruções da ligação voltam a ficar em modo síncrono.

Para saber quantas instruções assíncronas o driver suporta simultaneamente numa ligação, ligue SQLGetInfo com SQL_MAX_ASYNC_CONCURRENT_STATEMENTS. O Controlador ODBC 18 da Microsoft para o SQL Server devolve 1, por isso conte com apenas uma operação assíncrona pendente por ligação e abra mais ligações ou utilize threads para além disso. Ver Execução assíncrona (método de sondagem).

Os threads são a outra forma de manter várias operações em funcionamento. O ODBC exige que os drivers em sistemas operativos com múltiplas threads sejam seguros em ambientes multithread, para que uma thread possa fazer uma chamada ODBC bloqueadora enquanto outras threads continuam a executar. Isso evita o ciclo de consulta e as chamadas repetidas de funções de que o modo assíncrono necessita. Atribua a cada thread o seu próprio identificador de instrução. É provável que um controlador serialize duas threads que usem o mesmo handle em simultâneo, pelo que partilhá-lo implica perder concorrência. Consulte Multithreading. Prefira linhas de execução para código novo e meça a sua própria carga de trabalho antes de converter código assíncrono que já funciona.

No Windows, o gestor de drivers também suporta o método de notificação, que remove o ciclo de sondagens. Associe um evento Win32 à conexão ou ao identificador da instrução. A função continua a devolver SQL_STILL_EXECUTING imediatamente, e o gestor de controladores sinaliza o evento quando a operação estiver concluída. O polling está desativado neste modo: voltar a chamar a função original devolve SQL_ERROR com SQLSTATE IM017. Ligue SQLCompleteAsync para obter o resultado em vez disso. Isto precisa do gestor de drivers versão ODBC 3.81 e versões posteriores, e o driver também tem de suportá-lo. Chame SQLGetInfo com SQL_ASYNC_NOTIFICATION para verificar. O valor que recebes de volta depende da versão ODBC que a tua aplicação declara: com o Microsoft ODBC Driver 18 para SQL Server, uma aplicação que define SQL_ATTR_ODBC_VERSION para SQL_OV_ODBC3_80 gets SQL_ASYNC_NOTIFICATION_CAPABLE, e outra que declara SQL_OV_ODBC3 gets SQL_ASYNC_NOTIFICATION_NOT_CAPABLE a partir desse mesmo driver. Declare SQL_OV_ODBC3_80 antes de atribuir a ligação. Veja Execução assíncrona (método de notificação) e exemplo do método de notificação.

Cancelar uma operação pendente

SQLCancel cancela uma operação que ainda está em execução associada a um identificador de instrução. Chame-o a partir de outra thread, ou do ciclo de polling, passando o identificador da chamada pendente.

Usa SQLCancel apenas para isso. Para abandonar um conjunto de resultados que já não pretende ler, chame SQLCloseCursor ou SQLMoreResults em vez disso.

Migrar de sqlncli.h para msodbcsql.h

O SQL Server Native Client está desativado, por isso as aplicações que o utilizam devem passar para o Microsoft ODBC Driver for SQL Server. A API é a mesma API ODBC, por isso a maior parte do trabalho envolve renomear entradas de build e o nome do driver na cadeia de ligaçã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 msodbcsql.h cabeçalho ainda define os SQLNCLI_* nomes macros, por isso o código-fonte que os utiliza continua a compilar. Estas definições são protegidas por #ifndef __sqlncli_h__, o que significa que não pode incluir ambos os cabeçalhos na mesma unidade de tradução. Remova a sqlncli.h inclusão.

Duas coisas não se mantêm:

  • As funções distribuídas da API de metadados de consulta que retornam listas de servidores ligados e os seus catálogos não são declaradas em msodbcsql.h. Eram específicas para o SQL Server Native Client.
  • A versão 18 encripta as ligações por defeito e valida o certificado do servidor. O Cliente Nativo não o fez. Uma cadeia de ligação que funcionava com o Native Client pode falhar na primeira tentativa de ligação até corrigir a confiança no certificado ou definir Encrypt explicitamente. Veja Resolução de problemas de encriptação de ligação.

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