Controlador ODBC de Microsoft para SQL Server

Descargar controlador ODBC

ODBC es una interfaz nativa de programación de aplicaciones (API) para acceso a datos para aplicaciones escritas en C y C++. El controlador ODBC de Microsoft para SQL Server se conecta a SQL Server, Azure SQL Database, Azure SQL Managed Instance, Azure Synapse Analytics y la base de datos SQL en Microsoft Fabric. Para las versiones de base de datos que soporta cada versión de controlador, véase compatibilidad de versiones SQL.

Tu aplicación llama al gestor de controladores ODBC, que carga el controlador y le pasa las llamadas ODBC. Usa el administrador de controladores ODBC de Windows en Windows y unixODBC en Linux y macOS.

Otros lenguajes que pueden usar ODBC incluyen COBOL, Perl, PHP y Python. ODBC se utiliza ampliamente en escenarios de integración de datos, y los controladores de Microsoft para PHP para SQL Server se basan en este controlador.

La variante ODBC de sqlcmd y la utilidad bcp usan este controlador, pero se instalan por separado: el mssql-tools18 paquete en Linux y macOS, y las utilidades de línea de comandos de Microsoft en Windows. La variante Go de sqlcmd no usa este controlador. Utiliza sqlcmd para ejecutar sentencias Transact-SQL (T-SQL), procedimientos de sistema y archivos de script. Usa bcp para copiar datos en masa entre una instancia de SQL Server y un archivo de datos, en cualquier dirección.

Elija el punto de partida.

Línea base de producción para Azure SQL

Utiliza este programa completo en C++17 como punto de partida para una aplicación alojada en Azure. Conecta, ejecuta SELECT 1, comprueba el resultado y libera los handles ODBC. Instala Driver 18 y los archivos de desarrollo ODBC de la plataforma antes de compilarlo. Para requisitos previos, véase Desarrollar aplicaciones en C y C++ con el controlador ODBC.

Configura ODBC_CONNECTION_STRING en el entorno de la aplicación con tu cadena de conexión completa. El siguiente ejemplo utiliza una identidad gestionada asignada por el sistema. El host debe tener esa identidad habilitada y la base de datos debe concederle acceso. Para los requisitos de host, las identidades asignadas por el usuario y la autenticación de desarrollo local, consulte Usar Microsoft Entra ID con el controlador 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 requiere un punto final que soporte Tabular Data Stream (TDS) 8.0. En otros casos, use Encrypt=yes;TrustServerCertificate=no. Configura un certificado en el que el cliente confíe y cuyo nombre coincida con el nombre del servidor. Para configuración y verificación, consulta Solución de problemas de cifrado de conexión.

Mantén las credenciales fuera de los archivos fuente y del historial del shell. Para ver los comandos para establecer la variable de entorno, consulte Configurar la conexión. En Linux y macOS, proporciona su valor como UTF-8. Guarde el siguiente programa como 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;
    }
}

El programa solicita un tiempo de espera de conexión de 30 segundos para cada uno de los cuatro intentos como máximo y un tiempo de espera de consulta de 10 segundos. Entre intentos fallidos de conexión transitoria, espera 10, 20 y 40 segundos, cada uno con 0 a 250 milisegundos de jitter aleatorio. Estos límites no imponen un plazo límite general y estricto para la autenticación. El ejemplo clasifica errores de conexión transitorios seleccionados; adapta la política a tu carga de trabajo con el catálogo de errores de fallo transitorio de Azure SQL. No vuelve a intentar comandos de aplicación ni operaciones de escritura.

ConnectRetryCount y ConnectRetryInterval configuran la resiliencia de la conexión para conexiones elegibles que se caigan mientras están inactivas. No vuelven a intentar la conexión inicial ni vuelven a ejecutar los comandos de la aplicación. Mantén los retrasos de recuperación en reposo más cortos que el timeout de la consulta. La muestra registra valores SQLSTATE y números de error nativos en lugar de cadenas de conexión o mensajes de diagnóstico completos. Si necesitas el texto del mensaje para solucionar problemas, guárdalo en un registro de diagnóstico protegido.

Compila y ejecuta la línea de base

Utiliza un entorno de compilador que se ajuste a la arquitectura del procesador de tu aplicación. En Windows, ejecuta los comandos en Developer PowerShell para Visual Studio. En Linux y macOS, usa un shell con tu compilador y los archivos de desarrollo de unixODBC disponibles.

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

Una primera conexión exitosa imprime la siguiente salida. También podrían aparecer registros diagnósticos adicionales.

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

Limpia ODBC_CONNECTION_STRING cuando termines: usa Remove-Item Env:\ODBC_CONNECTION_STRING en PowerShell, o unset ODBC_CONNECTION_STRING en Bash o Zsh.

Para los oyentes de grupos de disponibilidad y la configuración de conmutación por error, utiliza Alta disponibilidad y recuperación ante desastres.

Características clave

  • Multiplataforma: La misma API en Windows, Linux y macOS.
  • Autenticación Microsoft Entra ID: Identidad gestionada, principal de servicio e autenticación integrada, además de autenticación interactiva en Windows. Los métodos disponibles dependen del host y la configuración de la base de datos.
  • Cifrado estricto: conexiones TDS 8.0 con validación completa de certificados en la versión 18 y versiones posteriores.
  • Always Encrypted: Cifrado en el lado del cliente para columnas sensibles, con soporte para proveedores de tiendas de claves personalizadas.
  • Resiliencia de la conexión: Restauración transparente de una conexión que se cayó mientras estaba en reposo.
  • Alta disponibilidad: compatibilidad con el listener de grupos de disponibilidad con MultiSubnetFailover.
  • Clasificación de datos: Metadatos de sensibilidad para columnas clasificadas.
  • Tipo de dato vectorial: Soporte nativo para el tipo vectorial .
  • Transacciones distribuidas: soporte para transacciones XA a través del Coordinador de transacciones distribuidas de Microsoft (MSDTC).
  • Herramientas complementarias: sqlcmd y bcp, instalados por separado.

Empieza ahora

Artículo Description
Descargar controlador ODBC para SQL Server Descargas de instaladores y paquetes para todas las versiones de controladores compatibles, en las tres plataformas.
Desarrollar aplicaciones en C y C++ con el controlador ODBC Qué cabeceras incluir, en qué orden, qué bibliotecas enlazar y cómo elegir entre ejecución asíncrona e hilos.
Conectarse y consultar una base de datos con C++ Un ejemplo completo de C++ que conecta, ejecuta una consulta y lee los resultados, para que puedas confirmar tu configuración de principio a fin.
Ciclo de vida de soporte técnico ¿Qué versiones de controladores siguen teniendo soporte y en qué fecha deja de tenerlo cada una?
Diferencias de la versión principal ¿Qué se rompe al pasar de la versión 17 a la versión 18, empezando con el cambio del valor predeterminado del cifrado?

Instalación del controlador

Artículo Description
Requisitos del sistema, archivos de instalación y controladores (Windows) Versiones de Windows compatibles, la línea de comandos del instalador para el despliegue silencioso y dónde aterriza cada archivo controlador en el disco.
Requisitos del sistema (Linux y macOS) Qué distribuciones de Linux y qué versiones de macOS admite cada versión del controlador, además de la compatibilidad con las versiones de SQL Server.
Instala el controlador ODBC en Linux Pasos del gestor de paquetes para Alpine, Debian, Red Hat, SUSE, Ubuntu y Azure Linux, además de la instalación offline y la ubicación de los archivos de los drivers.
Instala el controlador ODBC en macOS Pasos de tap y fórmula de Homebrew para macOS, incluyendo cómo instalar las versiones 18, 17 o 13.1.
Instala el gestor de controladores unixODBC (Linux y macOS) Instala o actualiza unixODBC, el gestor de controladores que carga el controlador ODBC en Linux y macOS.

Configuración y conexión

Artículo Description
Palabras clave y atributos de DSN y de la cadena de conexión El catálogo completo de palabras clave de cadena de conexión, entradas DSN y atributos SQLSetConnectAttr, con los valores aceptados para cada uno.
Palabras clave de cadenas de conexión y nombres de fuentes de datos (Linux y macOS) Cómo odbc.ini y odbcinst.ini definen una DSN en Linux y macOS, además de configuraciones de Seguridad de la Capa de Transporte (TLS) y el Protocolo de Control de Transmisión (TCP) específicas de esas plataformas.
Administrador de Fuentes de Datos ODBC DSN (Windows) Configura una fuente de datos a través de la interfaz de usuario de Windows en lugar de una cadena de conexión.
Agrupación de conexiones con reconocimiento del controlador (Windows) ¿Qué palabras clave y atributos de la cadena de conexión hacen que una conexión tenga su propio grupo de conexiones, y cuáles requieren una ida y vuelta adicional para restablecerla?

Autenticar y asegurar

Artículo Description
Utiliza Microsoft Entra ID con el controlador ODBC Todos los valores de las palabras clave Authentication, desde identidad administrada y entidad de servicio hasta interactivo e integrado, con la configuración que requiere cada uno.
Usa Always Encrypted con el controlador ODBC Cifra los valores sensibles de las columnas antes de enviarlos a la base de datos, con el resumen de la API del controlador y las limitaciones documentadas.
Clasificación de datos Lee las etiquetas de sensibilidad que el servidor asigna a las columnas clasificadas, para que tu aplicación pueda aplicar su propia política de protección de datos.
Utiliza autenticación integrada (Linux y macOS) Configura Kerberos para que un cliente de Linux o macOS pueda conectarse con credenciales de Windows en lugar de un inicio de sesión de SQL Server.

Alta disponibilidad y resistencia

Artículo Description
Resistencia de conexión Cómo ConnectRetryCount y ConnectRetryInterval restablecen una conexión cuando el servidor la interrumpe mientras está inactivo, y los errores IMCxx que devuelve el controlador cuando la recuperación no es posible.
Alta disponibilidad y recuperación ante desastres Conéctate a través de un listener de grupo de disponibilidad y usa MultiSubnetFailover para que la conmutación por error no se bloquee por un tiempo de espera de subred.
Utiliza una resolución IP de red transparente Cómo el respaldo heredado TransparentNetworkIPResolution ordena los intentos de conexión a través de múltiples direcciones de Protocolo de Internet (IP), y por qué MultiSubnetFailover lo supera.

Trabajar con datos

Artículo Description
Tipo de datos vectorial Vincular, enviar y recuperar el tipo vector, incluida su representación nativa de C y la compatibilidad con la copia masiva.
Utiliza transacciones XA con DTC Inscribe SQL Server en una transacción distribuida a través del Coordinador de transacciones distribuidas de Microsoft en Windows, Linux o macOS.
Directrices de programación (Linux y macOS) Encuentra orientación de programación para Linux y macOS, incluyendo el estado de las características, consideraciones sobre conjuntos de caracteres, OpenSSL y Alpine Linux.

Diagnóstico y solución de problemas

Artículo Description
Solución de problemas de cifrado de conexión Corrige los errores de certificado y de cifrado que presenta la versión 18, ya que cifra de forma predeterminada.
Trazado de acceso a datos (Linux y macOS) Activa el rastreo de conductores y captura un archivo de registro cuando necesites ver las llamadas que realmente realiza tu aplicación.
Problemas conocidos (Linux y macOS) Defectos confirmados y sus soluciones alternativas. Consulte aquí antes de abrir un caso de soporte.
Preguntas frecuentes (Linux y macOS) Respuestas breves a las preguntas que surgen más a menudo sobre el controlador en Linux y macOS.

Notas de lanzamiento y correcciones de errores

Artículo Description
Notas de versión para Windows Nuevas funciones, cambios de comportamiento y correcciones en cada versión de controladores de Windows.
Notas de lanzamiento para Linux y macOS Nuevas funciones, cambios de comportamiento y correcciones en cada versión de controladores de Linux y macOS.
Notas de versión para las herramientas de SQL Server Cambios en las utilidades sqlcmd y bcp , que se instalan por separado del controlador en Linux y macOS.

Reference

Artículo Description
Controlador ODBC en Windows Un resumen versión por versión de lo que soporta el controlador en Windows y un índice de los artículos específicos de Windows.
Características del controlador ODBC en Windows ¿Qué versión introdujo cada función de Windows, además de los cambios de comportamiento que conlleva.

Solicitud de una característica

Para solicitar una funcionalidad, presenta una idea a través de SQL Server feedback.