Desarrollar aplicaciones en C y C++ con el controlador ODBC

Versión: 18.7.1.1
Fecha: 7 de septiembre de 2026

Para llamar a la API ODBC desde C o C++, incluye sql.h, sqlext.h, y sqltypes.h, y luego enlaza contra la biblioteca de importación del gestor de controladores. Para utilizar las extensiones de SQL Server que el controlador ODBC de Microsoft para SQL Server añade sobre el estándar ODBC, incluye también msodbcsql.h, e inclúyelo después de los encabezados ODBC principales.

Aplica a: Microsoft ODBC Driver 18 para SQL Server en Windows, Linux y macOS. La versión 17 usa el mismo nombre de cabecera con una 170 ruta de instalación y un nombre de msodbcsql17 biblioteca.

Encabezados y bibliotecas

La plataforma proporciona los encabezados ODBC principales y el gestor de controladores, no el paquete de controladores. En Windows, se incluyen en el SDK de Windows. En Linux y macOS, vienen en el paquete de desarrollo unixODBC. El SDK del controlador solo proporciona msodbcsql.h y la biblioteca de importación de copia masiva.

Lo que llamas Headers Windows Linux macOS
API de ODBC sql.h, sqlext.h, sqltypes.h odbc32.lib -lodbc -lodbc
API ODBC, puntos de entrada Unicode Añadir sqlucode.h odbc32.lib -lodbc -lodbc
API de instalador ODBC Añadir odbcinst.h odbccp32.lib -lodbcinst -lodbcinst
Extensiones de controladores de SQL Server Añadir msodbcsql.h No hay biblioteca extra No hay biblioteca extra No hay biblioteca extra
Funciones de copia masiva (bcp_*) Añadir msodbcsql.h msodbcsql18.lib -lmsodbcsql-18 -lmsodbcsql.18

El nombre del enlace de copia masiva varía según la plataforma porque los nombres de los archivos varían. En Linux, -lmsodbcsql-18 se resuelve mediante un libmsodbcsql-18.so enlace simbólico en /usr/lib, que el enlazador ya busca, así que no necesitas -L. En macOS, el controlador se distribuye como libmsodbcsql.18.dylib, que -lmsodbcsql.18 reconoce, pero el directorio de bibliotecas de Homebrew no está en la ruta de búsqueda predeterminada en Apple silicon. Añade -L$(brew --prefix)/lib cuando enlaces las funciones de copia masiva.

Solo las funciones de copia masiva necesitan la propia biblioteca del controlador. Los atributos de conexión, atributos de sentencia, atributos de columna e identificadores de tipo SQL Server son macros y definiciones de tipos, por lo que incluir msodbcsql.h es suficiente para ellos.

La API del instalador es una biblioteca separada de la API ODBC. Llamar a una función como SQLGetPrivateProfileString sin -lodbcinst en Linux o macOS produce un error en el enlazado por una referencia no definida, no durante la compilación.

Para instalar el paquete de desarrollo unixODBC que proporciona los encabezados principales en Linux y macOS, consulte Instalar el gestor de controladores unixODBC.

Incluye wchar.h antes que msodbcsql.h en código C en Linux y macOS

Las versiones de msodbcsql.h Linux y macOS declaran la interfaz de proveedor de almacenamiento de claves Always Encrypted usando wchar_t, pero no incluyen un encabezado que defina este tipo. En C++, wchar_t es una palabra clave, por lo que las unidades de traducción en C++ se construyen sin necesidad de cabeceras adicionales. En C, wchar_t es una definición de tipos, así que necesitas incluir <wchar.h> primero en una unidad de traducción de C:

#include <wchar.h>

Si no incluyes <wchar.h>, el compilador informa de errores unknown type name 'wchar_t' desde dentro de msodbcsql.h. Añadir la inclusión no supone ningún problema en Windows, así que añádela al código fuente compartido en lugar de ponerla detrás de una protección condicional por plataforma.

Incluya msodbcsql.h después de las cabeceras principales de ODBC

Todo lo que msodbcsql.h define más allá de las macros de nombre del controlador está dentro de un bloque #ifdef ODBCVER, y sql.h es lo que define ODBCVER. Si incluyes msodbcsql.h primero, el preprocesador se salta todo ese bloque y la cabecera no aporta nada. El compilador no emite ninguna advertencia.

/* 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 sql.h deja todo lo que hay dentro del ODBCVER bloque sin definir. El compilador indica el error en el punto donde se usa, no en la directiva include:

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

En Windows, debes incluir windows.h antes de los encabezados ODBC. Las copias de sqltypes.h y sql.h del SDK de Windows usan tipos de Windows como DWORD y LONG. msodbcsql.henvuelve sus estructuras de SQL Server en pshpack8.h y poppack.h. Sin windows.h, la compilación falla dentro de los propios encabezados del SDK.

Dónde se instalan los archivos SDK

Plataforma msodbcsql.h Biblioteca de copias masivas
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, con un /usr/lib/libmsodbcsql-18.so enlace simbólico
macOS $(brew --prefix msodbcsql18)/include/msodbcsql18 $(brew --prefix)/lib/libmsodbcsql.18.dylib

En Windows, la Lib carpeta contiene una subcarpeta para cada arquitectura de procesador que el instalador colocaba en la máquina, como x64, x86, o arm64. Añade la Include carpeta a la ruta de inclusión del compilador y la subcarpeta de arquitectura a la ruta de biblioteca del enlazador.

En Linux, el objeto compartido tiene versiones, se denomina como libmsodbcsql-18.6.so.2.1, y no lleva ningún SONAME. El paquete instala /usr/lib/libmsodbcsql-18.so que apunta a él, que es lo que hace que -lmsodbcsql-18 se resuelva sin una opción -L. Enlaza a través de ese enlace simbólico en lugar de nombrar el archivo versionado, para que una actualización de drivers no rompa tu compilación.

En macOS, Homebrew se instala en su propio prefijo, que es /opt/homebrew en Apple silicon y /usr/local en Intel. Ambos prefijos son enlaces simbólicos al directorio versionado de Cellar. Usa brew --prefix msodbcsql18 y brew --prefix unixodbc en tu script de compilación en lugar de codificar directamente cualquiera de los dos.

El número de la ruta indica la versión principal del controlador. La versión 17 se instala en ...\ODBC\170\SDK\ Windows y /opt/microsoft/msodbcsql17/ en Linux, y su biblioteca de importación es msodbcsql17.lib.

Para consultar el inventario completo de archivos por plataforma, consulte Requisitos de sistema, archivos de instalación y controladores (Windows),Instale el controlador ODBC en Linux e Instale el controlador ODBC en macOS.

Verifica tu configuración de construcción

Este programa se compila con los archivos de cabecera, se enlaza con el administrador de controladores y enumera los controladores que el administrador de controladores puede ver. No se conecta, así que separa un problema de compilación o registro de un problema de red o credenciales.

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

Constrúyelo como un programa de caracteres estrechos. SQLODBC_DRIVER_NAME se expande a una cadena ancha cuando UNICODE o _UNICODE están definidos, que printf con %s no admite.

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

En Windows, /W4 informa de dos advertencias C4201: nonstandard extension used: nameless struct/union procedentes de la copia de sqlext.h del SDK de Windows. Estas advertencias provienen del encabezado del SDK, no de tu código, y la compilación tiene éxito.

La primera línea informa el nombre del controlador compilado en tu binario. El resto es la propia lista del gestor de controladores, así que si un controlador que esperas ver no aparece, es un problema de registro, no de compilación. Tu lista será diferente, e incluye todos los controladores ODBC instalados, no solo los de 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)

Cree la cadena de conexión a partir de SQLODBC_DRIVER_NAME en lugar de hacerlo a partir de un literal de cadena. La macro toma como referencia el archivo de cabecera con el que compilaste, así que, al actualizar el SDK, se actualiza el nombre del controlador en un solo lugar.

Qué añade msodbcsql.h a la API ODBC

msodbcsql.hextiende la API estándar de ODBC con características específicas de SQL Server. Cada familia ocupa un rango numérico contiguo contado a partir de una constante base. Los rangos no son únicos entre familias, así que la función a la que le pasas el valor es lo que los diferencia.

Familia Constante base Value
Atributos de conexión para SQLSetConnectAttr SQL_COPT_SS_BASE 1200
Atributos de la instrucción para SQLSetStmtAttr SQL_SOPT_SS_BASE 1,225
Atributos de columna para SQLColAttribute SQL_CA_SS_BASE 1200
Tipos de información para SQLGetInfo SQL_INFO_SS_FIRST 1199
Campos diagnósticos para SQLGetDiagField SQL_DIAG_SS_BASE -1150
Códigos de función dinámica diagnóstica SQL_DIAG_DFC_SS_BASE -200

El encabezado también declara:

  • Atributos de autenticación, incluyendo SQL_COPT_SS_AUTHENTICATION y SQL_COPT_SS_ACCESS_TOKEN, que contienen la configuración del Microsoft Entra ID y los tokens de acceso.
  • Los identificadores de tipo SQL en el intervalo de -150 a -199 para los tipos de SQL Server que ODBC no define son: SQL_SS_VARIANT, SQL_SS_UDT, SQL_SS_XML, SQL_SS_TABLE, SQL_SS_TIME2, SQL_SS_TIMESTAMPOFFSET y SQL_SS_VECTOR. Estos indican un tipo SQL, por lo que se usan donde ODBC espera un tipo SQL, como el argumento ParameterType de SQLBindParameter.
  • Tres tipos C coincidentes para el lado del buffer: SQL_C_SS_TIME2, SQL_C_SS_TIMESTAMPOFFSET, y SQL_C_SS_VECTOR. Los otros tipos de SQL Server se asignan a un tipo C estándar de ODBC como SQL_C_BINARY o SQL_C_WCHAR, por lo que no tienen un equivalente SQL_C_SS_*.
  • Las estructuras a las que se vinculan los SQL_C_SS_* tipos: SQL_SS_TIME2_STRUCT, SQL_SS_TIMESTAMPOFFSET_STRUCT, y SQL_SS_VECTOR_STRUCT.
  • Prototipos y macros de copia masiva, incluyendo bcp_init, bcp_bind, bcp_sendrow, bcp_batch, y bcp_done. Las BCP_ENCRYPT_OFFopciones , BCP_ENCRYPT_ON, y BCP_ENCRYPT_STRICT están solo en el encabezado de Windows.

Cada plataforma envia su propia copia de msodbcsql.h, y no todas declaran los mismos símbolos. La SQLPERF estructura y los atributos de conexión de rendimiento que lo completan, como SQL_COPT_SS_PERF_DATA y SQL_COPT_SS_PERF_QUERY, están solo en el encabezado de Windows. Las cabeceras de Linux y macOS no las declaran, y el controlador no recopila datos de rendimiento en esas plataformas. Consulta las directrices de programación (Linux y macOS).

Para las palabras clave de cadena de conexión a las que corresponden estos atributos, véase DSN y palabras clave y atributos de cadena de conexión. Para la configuración de Microsoft Entra ID, véase Usar Microsoft Entra ID con el controlador ODBC. Para el tipo de vector , véase Tipo de dato vectorial.

Elige entre ejecución asíncrona e hilos

Algunas funciones ODBC pueden ejecutarse de forma síncrona o asíncrona. En modo síncrono, el controlador no devuelve el control hasta que responde el servidor. En modo asincrónico, el controlador regresa SQL_STILL_EXECUTING inmediatamente y la aplicación repite la misma llamada con los mismos argumentos hasta que recibe un código de retorno diferente. Cualquier otro código de retorno, incluyendo SQL_ERROR, significa que la operación ha terminado.

El modo asincrónico tiene dos formas, y se usa una de ellas. Llama a SQLGetInfo con SQL_ASYNC_MODE para averiguar cuál de ellos admite el controlador. Vuelve SQL_AM_STATEMENT si el controlador soporta control por sentencia, SQL_AM_CONNECTION si la configuración se aplica a toda la conexión, o SQL_AM_NONE si el controlador no ejecuta funciones de forma asíncrona en absoluto.

El formulario de sentencia activa el modo asíncrono para un handle de una sentencia. Todas las demás instrucciones en la conexión permanecen sincrónicas, así que puedes ejecutar ambos tipos al mismo tiempo:

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

Si SQL_ASYNC_MODE devuelve SQL_AM_CONNECTION, el atributo de la sentencia es de solo lectura y esta llamada devuelve SQL_ERROR con SQLSTATE HYC00. Usa el formulario de conexión en su lugar.

El formulario de conexión activa el modo asincrónico para cada identificador de instrucción que se asigne posteriormente en esa conexión. Que esto también afecte a los identificadores que ya existen depende del controlador, así que configúralo antes de asignar cualquier instrucción:

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

La llamada se devuelve SQL_ERROR con SQLSTATE HY010 si una función sigue ejecutándose de forma asíncrona en una instrucción para esa conexión. Un cursor abierto por sí solo no bloquea la llamada. Pasar SQL_ASYNC_ENABLE_OFF vuelve a poner todas las sentencias de la conexión en modo síncrono.

Para saber cuántas sentencias asíncronas soporta el controlador a la vez en una conexión, llama SQLGetInfo con SQL_MAX_ASYNC_CONCURRENT_STATEMENTS. El controlador ODBC 18 de Microsoft para SQL Server devuelve 1, así que planifica una operación asíncrona pendiente por conexión y abre más conexiones o usa hilos más allá de eso. Véase Ejecución asíncrona (método de sondeo).

Los hilos son la otra forma de mantener varias operaciones en vuelo. ODBC requiere que los controladores en sistemas operativos multihilo sean seguros para hilos, por lo que un hilo puede hacer una llamada ODBC bloqueante mientras otros hilos siguen funcionando. Eso evita el bucle de sondeo y las llamadas repetidas a funciones que necesita el modo asíncrono. Asigna a cada hilo su propio identificador de instrucción. Un controlador probablemente serializará dos hilos que usan el mismo handle al mismo tiempo, así que compartir uno te cuesta la concurrencia. Véase Multihilo. Prefiere hilos para el código nuevo y mide tu carga de trabajo antes de convertir código asíncrono que ya funciona.

En Windows, el administrador de controladores también soporta el método de notificación, que elimina el bucle de sondeo. Asocia un evento Win32 a un identificador de conexión o a un identificador de instrucción. La función sigue devolviendo SQL_STILL_EXECUTING inmediatamente, y el administrador de controladores señala el evento cuando se completa la operación. El sondeo está deshabilitado en este modo: si se vuelve a llamar a la función original, se devuelve SQL_ERROR con SQLSTATE IM017. Llame a SQLCompleteAsync para obtener el resultado en su lugar. Esto necesita la versión ODBC 3.81 y versiones posteriores del gestor de controladores, y el controlador también debe soportarlo. Llama a SQLGetInfo con SQL_ASYNC_NOTIFICATION para comprobarlo. El valor que se devuelve depende de la versión de ODBC que declare la aplicación: con Microsoft ODBC Driver 18 para SQL Server, una aplicación que establece SQL_ATTR_ODBC_VERSION en SQL_OV_ODBC3_80 obtiene SQL_ASYNC_NOTIFICATION_CAPABLE, y otra que declara SQL_OV_ODBC3 obtiene SQL_ASYNC_NOTIFICATION_NOT_CAPABLE de ese mismo controlador. Declara SQL_OV_ODBC3_80 antes de asignar la conexión. Véase Ejecución asíncrona (método de notificación) y el ejemplo de método de notificación.

Cancelar una operación pendiente

SQLCancel Cancela una operación que aún se está ejecutando en un handle de sentencia. Llámala desde otro hilo o desde el bucle de sondeo, pasando el identificador de la llamada pendiente.

Usa SQLCancel solo para eso. Para abandonar un conjunto de resultados que ya no desee leer, llame a SQLCloseCursor o SQLMoreResults en su lugar.

Migrar de sqlncli.h a msodbcsql.h

El cliente nativo de SQL Server está retirado, por lo que las aplicaciones que lo usan deberían pasar al controlador ODBC de Microsoft para SQL Server. La API es la misma API ODBC, por lo que la mayor parte del trabajo consiste en renombrar las entradas de compilación y el nombre del controlador en la cadena de conexión.

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

El archivo de cabecera msodbcsql.h sigue definiendo las macros de nombres SQLNCLI_*, así que el código fuente que las utiliza sigue compilando. Estas definiciones están protegidas por #ifndef __sqlncli_h__, lo que significa que no puedes incluir ambos encabezados en la misma unidad de traducción. Quita el sqlncli.h incluido.

Hay dos cosas que no se trasladan:

  • Las funciones distribuidas de la API de metadatos de consultas que devolven listas de servidores enlazados y sus catálogos no se declaran en msodbcsql.h. Eran específicos para SQL Server Native Client.
  • La versión 18 cifra las conexiones por defecto y valida el certificado del servidor. Native Client no lo hizo. Una cadena de conexión que funcionaba con Native Client puede fallar al establecer la primera conexión hasta que se corrija la confianza del certificado o se configure Encrypt explícitamente. Consulta Solución de problemas de cifrado de conexión.

Para el resto de los cambios de la versión 17 a la versión 18, véase Diferencias principales en las versiones.