Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Utiliza esta guía con el controlador ODBC 17 o 18 de Microsoft. Describe el contrato diagnóstico ODBC; no define mapeos nativos de error específicos de versión.
Una función ODBC devuelve un código que describe el resultado de esa llamada. Los registros diagnósticos proporcionan más detalles. La interfaz de programación de aplicaciones (API) puede devolver registros desde el Driver Manager, el controlador, la fuente de datos o más de un componente. No trates el código de retorno, SQLSTATE, código de error nativo y mensaje como intercambiables.
Interpretar el código de retorno
Comprueba el código de retorno antes de procesar la salida o decidir si quieres volver a intentarlo. Para SQL_ERROR y SQL_SUCCESS_WITH_INFO, recupera diagnósticos del handle utilizado por la función. Otros códigos de retorno también pueden tener registros diagnósticos cuando el contrato de función se lo permite.
| Código de retorno | Significado y respuesta |
|---|---|
SQL_SUCCESS |
La función se completó correctamente. Comprueba el contrato de salida de la función. |
SQL_SUCCESS_WITH_INFO |
La función se completó con información de advertencia. Recupera cada registro diagnóstico y comprueba si la salida está completa, convertida o truncada. |
SQL_ERROR |
La función falló. Recupera todos los registros diagnósticos antes de llamar a otra función en el mismo identificador. |
SQL_INVALID_HANDLE |
La función detectó un handle nulo o un handle de tipo incorrecto. ODBC no proporciona registros diagnósticos para este código de devolución. Consulta la referencia de función para conocer los requisitos adicionales de los identificadores. |
SQL_NO_DATA |
No hay más datos disponibles para la operación. Comprueba la referencia de la función porque el significado y cualquier registro de estado dependen de la función. |
Para más información sobre el contrato completo de códigos de retorno, consulte códigos de retorno ODBC.
Recuperar todos los registros diagnósticos
Ejecute SQLGetDiagRec para los registros de estado a partir del registro número 1. Continúa hasta que la función devuelva SQL_NO_DATA, o lee el recuento de registros desde el registro de cabecera 0 llamando SQLGetDiagField con SQL_DIAG_NUMBER.
SQLGetDiagRec devuelve el estado SQL, el código de error nativo y el texto del mensaje de un registro. Usa SQLGetDiagField cuando necesites otros campos de cabecera o registro.
No pares después del primer registro. Un componente ODBC puede añadir un registro de estado con información sobre su propia capa mientras preserva diagnósticos de otro componente. El orden y el contenido del registro pueden ayudar a identificar dónde se originó un error.
Recoge los datos con prontitud. Una llamada ODBC posterior que use el mismo handle reemplaza su área de diagnóstico, excepto las llamadas a SQLGetDiagRec, SQLGetDiagField, y la función heredada SQLError . Use SQLGetDiagRec y SQLGetDiagField en código nuevo.
SQLGetDiagRec puede regresar SQL_SUCCESS_WITH_INFO cuando su búfer de mensajes es demasiado pequeño. El registro fue devuelto, pero el texto del mensaje fue truncado. Comprueba la longitud del texto reportada y recupera el mensaje con un búfer más grande si necesitas el texto completo. No confundas este código de retorno SQLGetDiagRec con el código de retorno de la función ODBC original.
Para más información sobre la recuperación diagnóstica, consulte Registros de diagnóstico, Usando SQLGetDiagRec y SQLGetDiagField, y las referencias SQLGetDiagRec y SQLGetDiagField .
Recopilar registros de diagnóstico en C++
Utiliza este asistente en C++11 con un handle ODBC existente. Llama a SQLGetDiagRecW para recopilar SQLSTATE, código de error nativo y texto de mensajes Unicode en memoria sin registrar los mensajes.
#ifdef _WIN32
#include <windows.h>
#endif
#include <sql.h>
#include <sqlext.h>
#include <algorithm>
#include <limits>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
struct DiagnosticRecord {
std::string sqlstate;
SQLINTEGER native_error;
std::vector<SQLWCHAR> message;
bool message_truncated;
};
std::vector<DiagnosticRecord> ReadDiagnostics(SQLSMALLINT type, SQLHANDLE handle) {
const SQLSMALLINT limit = (std::numeric_limits<SQLSMALLINT>::max)();
std::vector<DiagnosticRecord> records;
for (SQLINTEGER number = 1; ; ++number) {
if (number > limit) {
throw std::runtime_error("Diagnostic record number exceeds SQLSMALLINT.");
}
SQLWCHAR state[6] = {};
SQLINTEGER native = 0;
std::vector<SQLWCHAR> message(256);
auto read = [&]() {
return SQLGetDiagRecW(type, handle, static_cast<SQLSMALLINT>(number),
state, &native, message.data(),
static_cast<SQLSMALLINT>(message.size()), nullptr);
};
SQLRETURN result = read();
if (result == SQL_NO_DATA) {
return records;
}
if (result == SQL_SUCCESS_WITH_INFO) {
message.resize(limit);
result = read(); // Retrieve the same record, not the next one.
}
if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
throw std::runtime_error("SQLGetDiagRecW couldn't retrieve a diagnostic record.");
}
message.erase(std::find(message.begin(), message.end(), SQLWCHAR{0}), message.end());
records.push_back({
std::string(state, state + 5),
native,
std::move(message),
result == SQL_SUCCESS_WITH_INFO
});
}
}
El ayudante intenta de nuevo un mensaje truncado con la mayor longitud positiva del búfer que SQLGetDiagRecW acepta. Si el mensaje sigue sin caber, mantiene el texto disponible y establece message_truncated. Continúa al siguiente registro en lugar de tratar ese truncamiento como el final de la lista diagnóstica. Se lanza si la recuperación falla o si el número de registro supera el rango de la API SQLSMALLINT.
Cada mensaje contiene SQLWCHAR unidades de código sin el terminador nulo. No los reinterpretes como wchar_t, porque los tipos pueden tener diferentes anchos. Conviértelos a la codificación de texto de tu aplicación cuando necesites procesar o mostrar el mensaje.
Llama a la función auxiliar inmediatamente después de la operación que devuelve un error o advertencia. Este fragmento asume que statement es un handle de sentencia válido y preparado y que la ejecución asíncrona está deshabilitada:
#include <iostream>
SQLRETURN ExecuteWithDiagnostics(SQLHSTMT statement) {
SQLRETURN result = SQLExecute(statement);
if (result == SQL_ERROR || result == SQL_SUCCESS_WITH_INFO) {
const auto records = ReadDiagnostics(SQL_HANDLE_STMT, statement);
for (const auto& record : records) {
std::cerr << "SQLExecute: SQLSTATE=" << record.sqlstate
<< " native_error=" << record.native_error
<< " message_truncated=" << record.message_truncated << '\n';
}
} else if (result == SQL_INVALID_HANDLE) {
throw std::runtime_error("SQLExecute returned SQL_INVALID_HANDLE.");
}
return result;
}
El envoltorio conserva el código de retorno original, incluyendo SQL_SUCCESS_WITH_INFO. Aplica el mismo patrón a otras llamadas ODBC, usando el tipo de handle y handle asociados a esa operación. Maneja otros códigos de retorno según el contrato de esa función.
La salida omite record.message deliberadamente. Si necesitas texto de mensaje en un registro, anonimízalo según la política de datos de tu aplicación antes de escribirlo. El ayudante no sanea los mensajes almacenados en memoria.
Lee los campos diagnósticos
Los campos responden a diferentes preguntas:
| Field | Lo que te dice |
|---|---|
| SQLSTATE | Un código de cinco caracteres que identifica una condición diagnóstica estandarizada. Su clase corresponde a los dos primeros caracteres. |
| Código de error nativo | Un valor específico para la fuente de datos o componente ODBC. No es un número de error universal, y no deberías asumir que es un número de error de SQL Server. |
| Texto del mensaje | Una explicación legible para humanos. Léelo con SQLSTATE y código de error nativo; no lo proceses como un contrato estable y legible por máquina. |
El Driver Manager, el driver y la fuente de datos pueden generar diagnósticos cada uno. Un componente que añade un registro no debe reemplazar ni enmascarar un error o advertencia de otro componente. Un código de error nativo puede no estar disponible o no tener un significado útil para un diagnóstico generado por componentes. Para más información sobre las reglas del componente, véase Reglas de manejo diagnóstico. Para más información sobre las clases y valores SQLSTATE, véase SQLSTATEs.
Utiliza los registros junto con el código de retorno de la función y la operación. Por ejemplo, SQL_SUCCESS_WITH_INFO significa que la función se ha completado, pero no garantiza que todos los valores de salida estén completos. Una advertencia de truncamiento requiere que compruebes la longitud devuelta y decidas si recuperar los datos restantes. Para más información, consulta Longitud de datos, longitud del búfer y truncamiento.
Recopila pruebas de forma segura
Para un caso de soporte, registra el nombre de la función, el tipo de handle, el código de retorno y cada registro diagnóstico. Incluye las versiones del controlador y del Administrador de Controladores, el sistema operativo, la arquitectura y el tipo de fuente de datos. Oculta credenciales, tokens de acceso, secretos de cadena de conexión, texto de consulta, valores de parámetros y datos personales o regulados antes de guardar o compartir la salida. Los mensajes de diagnóstico y los registros de trazado pueden contener datos de la aplicación.
Limita el seguimiento al caso de reproducción más corto que necesites. Almacenar los registros en un directorio accesible solo para la cuenta que ejecuta la aplicación y usar una ruta de registro explícita en lugar de una predeterminada compartida o temporal. Deja de rastrear cuando termine la reproducción y luego elimina el archivo de trazado cuando ya no lo necesites.
Elige la capa de vectorización
El diagnóstico y el rastreo de aplicaciones responden a diferentes preguntas:
| Nivel | Lo que captura | Úselo para |
|---|---|---|
| Diagnósticos de aplicaciones | Códigos de retorno y registros diagnósticos de llamadas individuales ODBC | Identifica la función que falló o devolvió una advertencia y conserva todos sus campos diagnósticos. |
| Trazado ODBC Driver Manager | Llamadas a la API ODBC entre la aplicación, el Gestor de Controladores y el controlador | Mira qué llamadas hizo la aplicación y qué códigos de retorno han devuelto. Los argumentos de rastreo pueden exponer valores sensibles. |
| Traza específica del controlador | Eventos internos del controlador, cuando el controlador documenta un control soportado | Investiga el comportamiento del controlador que un rastreo de API no puede mostrar. No des por hecho que un rastreo de Driver Manager habilita esta funcionalidad. |
En Windows, el Administrador de controladores ODBC admite el trazado a través de la pestaña Tracing en ODBC Data Source Administrator y los atributos SQL_ATTR_TRACE y SQL_ATTR_TRACEFILE. El trazado es por usuario por defecto. El trazado a nivel de máquina requiere permisos de administrador local y puede capturar llamadas de aplicaciones que se ejecutan bajo otras identidades locales. Prefiera el seguimiento por usuario y deténgalo en cuanto termine la reproducción del problema. Para más información, consulta Configurar las opciones de trazado, Habilitar el trazado y SQLSetConnectAttr.
En Linux y macOS, consulta Seguimiento del acceso a datos con el controlador ODBC en Linux y macOS para la configuración del administrador de controladores unixODBC.
Las Directrices de Programación de Linux y macOS existentes mantienen una declaración histórica de que el seguimiento BID incorporado no fue verificado antes del controlador ODBC 17.3. Esa nota no describe un control de traza específico del controlador actual. El procedimiento unixODBC captura llamadas a la API del Driver Manager, no eventos BID.