Procesar errores de ODBC (ODBC)
Se aplica a: SQL Server Azure SQL Database Azure SQL Instancia administrada Azure Synapse Analytics Analytics Platform System (PDW)
Se pueden usar dos llamadas a la función de ODBC para recuperar los mensajes de ODBC: SQLGetDiagRec y SQLGetDiagField. Para obtener la información principal relacionada con ODBC de los campos de diagnóstico SQLState, pfNative y ErrorMessage, llame a SQLGetDiagRec hasta que devuelva SQL_NO_DATA. Para cada registro de diagnóstico, se puede llamar a SQLGetDiagField para recuperar los campos individuales. Todos los campos específicos del controlador se deben recuperar usando SQLGetDiagField.
SQLGetDiagRec y SQLGetDiagField los procesa el Administrador de controladores ODBC, no un controlador individual. El Administrador de controladores ODBC no almacena en memoria caché los campos de diagnóstico específicos del controlador hasta que no se ha realizado una conexión correcta. No se puede llamar a SQLGetDiagField para los campos de diagnóstico específicos del controlador antes de que la conexión no sea correcta. Esto incluye los comandos de conexión ODBC, aun cuando devuelvan SQL_SUCCESS_WITH_INFO. Los campos de diagnóstico específicos del controlador no estarán disponibles hasta la llamada a función de ODBC siguiente.
Ejemplo
Descripción
En este ejemplo se muestra un controlador de errores simple que llama a SQLGetDiagRec para la información ODBC estándar. A continuación, comprueba si hay una conexión válida y, si existe, llama a SQLGetDiagField para los campos de diagnóstico específicos del controlador ODBC de SQL Server. Este ejemplo no es compatible con IA64.
Este ejemplo se desarrolló para la versión 3.0 o posterior de ODBC.
Importante
Siempre que sea posible, utilice la autenticación de Windows. Si la autenticación de Windows no está disponible, solicite a los usuarios que escriban sus credenciales en tiempo de ejecución. No guarde las credenciales en un archivo. Si tiene que conservar las credenciales, debería cifrarlas con la API de criptografía de Win32.
Necesitará un origen de datos ODBC denominado AdventureWorks, cuya base de datos predeterminada sea la base de datos de ejemplo AdventureWorks. (Puede descargar la base de datos de ejemplo AdventureWorks desde Página principal ejemplos de Microsoft SQL Server y proyectos de comunidad). Este origen de datos debe basarse en el controlador ODBC proporcionado por el sistema operativo (el nombre del controlador es "SQL Server"). Si genera y ejecuta este ejemplo como una aplicación de 32 bits en un sistema operativo de 64 bits, debe crear el origen de datos ODBC con el Administrador ODBC en %windir%\SysWOW64\odbcad32.exe.
Este ejemplo se conecta a la instancia predeterminada de SQL Server del equipo. Para conectarse a una instancia con nombre, cambie la definición del origen de datos ODBC para especificar la instancia utilizando el formato servidor\instanciaConNombre. De forma predeterminada, SQL Server Express se instala en una instancia con nombre.
Ejecute la primera lista de código (Transact-SQL) para crear el procedimiento almacenado usado por este ejemplo.
Compile el segundo fragmento de código (C++) con odbc32.lib. A continuación, ejecute el programa.
Ejecute la tercera lista de código (Transact-SQL) para eliminar el procedimiento almacenado usado por este ejemplo.
Código
USE AdventureWorks2022;
IF EXISTS (SELECT name FROM sysobjects WHERE name = 'BadOne')
DROP PROCEDURE BadOne
Go
CREATE PROCEDURE BadOne
AS
SELECT * FROM Purchasing.Vendor
Go
Código
// compile with: odbc32.lib
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>
#define MAXBUFLEN 256
SQLHENV henv = SQL_NULL_HENV;
SQLHDBC hdbc1 = SQL_NULL_HDBC;
SQLHSTMT hstmt1 = SQL_NULL_HSTMT;
void ProcessLogMessages(SQLSMALLINT plm_handle_type, SQLHANDLE plm_handle, char *logstring, int ConnInd);
void Cleanup() {
if (hstmt1 != SQL_NULL_HSTMT)
SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
if (hdbc1 != SQL_NULL_HDBC) {
SQLDisconnect(hdbc1);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
}
if (henv != SQL_NULL_HENV)
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
int main() {
RETCODE retcode;
// Allocate the ODBC environment and save handle.
retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
printf("SQLAllocHandle(Env) Failed\n\n");
Cleanup();
return(9);
}
// Notify ODBC that this is an ODBC 3.0 app.
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);
if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
printf("SQLSetEnvAttr(ODBC version) Failed\n\n");
Cleanup();
return(9);
}
// Allocate ODBC connection handle and connect.
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
printf("SQLAllocHandle(hdbc1) Failed\n\n");
Cleanup();
return(9);
}
// This sample use Integrated Security. Please create the SQL Server
// DSN by using the Windows NT authentication.
retcode = SQLConnect(hdbc1, (UCHAR*)"AdventureWorks", SQL_NTS, (UCHAR*)"",SQL_NTS, (UCHAR*)"", SQL_NTS);
if ( (retcode != SQL_SUCCESS) &&
(retcode != SQL_SUCCESS_WITH_INFO) ) {
ProcessLogMessages(SQL_HANDLE_DBC, hdbc1, "SQLConnect() Failed\n\n", FALSE);
Cleanup();
return(9);
}
else {
ProcessLogMessages(SQL_HANDLE_DBC, hdbc1,
"\nConnect Successful\n\n", FALSE);
}
// Allocate statement handle, and then execute command.
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);
if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
ProcessLogMessages(SQL_HANDLE_DBC, hdbc1, "SQLAllocHandle(hstmt1) Failed\n\n", TRUE);
Cleanup();
return(9);
}
retcode = SQLExecDirect(hstmt1, (UCHAR*)"exec BadOne", SQL_NTS);
if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
ProcessLogMessages(SQL_HANDLE_STMT, hstmt1, "SQLExecute() Failed\n\n", TRUE);
Cleanup();
return(9);
}
// Clear any result sets generated.
while ( ( retcode = SQLMoreResults(hstmt1) ) != SQL_NO_DATA )
;
// Clean up.
SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
SQLDisconnect(hdbc1);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
void ProcessLogMessages(SQLSMALLINT plm_handle_type, SQLHANDLE plm_handle, char *logstring, int ConnInd) {
RETCODE plm_retcode = SQL_SUCCESS;
UCHAR plm_szSqlState[MAXBUFLEN] = "", plm_szErrorMsg[MAXBUFLEN] = "";
SDWORD plm_pfNativeError = 0L;
SWORD plm_pcbErrorMsg = 0;
SQLSMALLINT plm_cRecNmbr = 1;
SDWORD plm_SS_MsgState = 0, plm_SS_Severity = 0;
SQLINTEGER plm_Rownumber = 0;
USHORT plm_SS_Line;
SQLSMALLINT plm_cbSS_Procname, plm_cbSS_Srvname;
SQLCHAR plm_SS_Procname[MAXNAME], plm_SS_Srvname[MAXNAME];
if (logstring)
printf(logstring);
while (plm_retcode != SQL_NO_DATA_FOUND) {
plm_retcode = SQLGetDiagRec(plm_handle_type, plm_handle, plm_cRecNmbr,
plm_szSqlState, &plm_pfNativeError, plm_szErrorMsg,
MAXBUFLEN - 1, &plm_pcbErrorMsg);
// Note that if the application has not yet made a successful connection,
// the SQLGetDiagField information has not yet been cached by ODBC Driver Manager and
// these calls to SQLGetDiagField will fail.
if (plm_retcode != SQL_NO_DATA_FOUND) {
if (ConnInd) {
plm_retcode = SQLGetDiagField( plm_handle_type, plm_handle, plm_cRecNmbr,
SQL_DIAG_ROW_NUMBER, &plm_Rownumber,
SQL_IS_INTEGER, NULL);
plm_retcode = SQLGetDiagField( plm_handle_type, plm_handle, plm_cRecNmbr,
SQL_DIAG_SS_LINE, &plm_SS_Line, SQL_IS_INTEGER, NULL);
plm_retcode = SQLGetDiagField( plm_handle_type, plm_handle, plm_cRecNmbr,
SQL_DIAG_SS_MSGSTATE, &plm_SS_MsgState,
SQL_IS_INTEGER, NULL);
plm_retcode = SQLGetDiagField( plm_handle_type, plm_handle, plm_cRecNmbr,
SQL_DIAG_SS_SEVERITY, &plm_SS_Severity,
SQL_IS_INTEGER, NULL);
plm_retcode = SQLGetDiagField( plm_handle_type, plm_handle, plm_cRecNmbr,
SQL_DIAG_SS_PROCNAME, &plm_SS_Procname,
sizeof(plm_SS_Procname), &plm_cbSS_Procname);
plm_retcode = SQLGetDiagField( plm_handle_type, plm_handle, plm_cRecNmbr,
SQL_DIAG_SS_SRVNAME, &plm_SS_Srvname,
sizeof(plm_SS_Srvname), &plm_cbSS_Srvname);
}
printf("szSqlState = %s\n", plm_szSqlState);
printf("pfNativeError = %d\n", plm_pfNativeError);
printf("szErrorMsg = %s\n", plm_szErrorMsg);
printf("pcbErrorMsg = %d\n\n", plm_pcbErrorMsg);
if (ConnInd) {
printf("ODBCRowNumber = %d\n", plm_Rownumber);
printf("SSrvrLine = %d\n", plm_Rownumber);
printf("SSrvrMsgState = %d\n", plm_SS_MsgState);
printf("SSrvrSeverity = %d\n", plm_SS_Severity);
printf("SSrvrProcname = %s\n", plm_SS_Procname);
printf("SSrvrSrvname = %s\n\n", plm_SS_Srvname);
}
}
plm_cRecNmbr++; // Increment to next diagnostic record.
}
}
Código
USE AdventureWorks2022;
DROP PROCEDURE BadOne
GO