Processar erros ODBC (ODBC)
Aplica-se a: SQL Server Banco de Dados SQL do Azure Instância Gerenciada de SQL do Azure Azure Synapse Analytics Analytics Platform System (PDW)
É possível usar duas chamadas de função ODBC para recuperar mensagens ODBC: SQLGetDiagRec e SQLGetDiagField. Para obter informações relacionadas ao ODBC principal nos campos de diagnóstico SQLState, pfNative e ErrorMessage, chame SQLGetDiagRec até ele retornar SQL_NO_DATA. Para cada registro de diagnóstico, é possível chamar SQLGetDiagField a fim de recuperar campos individuais. Todos os campos específicos do driver devem ser recuperados usando SQLGetDiagField.
SQLGetDiagRec e SQLGetDiagField são processados pelo Gerenciador de Driver ODBC, não por um driver individual. O Gerenciador de Driver ODBC não armazena em cache campos de diagnóstico específicos do driver até que seja feita uma conexão bem-sucedida. Não é possível chamar SQLGetDiagField para campos de diagnóstico específicos do driver antes de obter uma conexão bem-sucedida. Isso inclui os comandos de conexão ODBC, mesmo se eles retornarem SQL_SUCCESS_WITH_INFO. Os campos de diagnóstico específicos do driver não estarão disponíveis até a próxima chamada de função ODBC.
Exemplo
Descrição
O exemplo mostra um manipulador de erros simples que chama SQLGetDiagRec para as informações ODBC padrão. Em seguida, ele testa uma conexão válida e, se houver, chama SQLGetDiagField para os campos de diagnóstico específicos do driver ODBC do SQL Server. Este exemplo não tem suporte em IA64.
Esse exemplo foi desenvolvido para o ODBC versão 3.0 ou posterior.
Importante
Quando possível, use a Autenticação do Windows. Se a Autenticação do Windows não estiver disponível, solicite aos usuários que digitem suas credenciais em tempo de execução. Evite armazenar as credenciais em um arquivo. Se for necessário manter as credenciais, criptografe-as com a Win32 crypto API(em inglês).
Será necessária uma fonte de dados ODBC chamada AdventureWorks, cujo banco de dados padrão é o banco de dados de exemplo AdventureWorks. (Você pode baixar o banco de dados de exemplo AdventureWorks no Home page de Exemplos e Projetos da Comunidade do Microsoft SQL Server.) Essa fonte de dados deve ser baseada no driver ODBC fornecido pelo sistema operacional (o nome do driver é "SQL Server"). Se você compilar e executar esse exemplo como um aplicativo de 32 bits em um sistema operacional de 64 bits, deverá criar a fonte de dados ODBC com o Administrador ODBC em %windir%\SysWOW64\odbcad32.exe.
Este exemplo se conecta à instância padrão do SQL Server do computador. Para conectar-se a uma instância nomeada, altere a definição da fonte de dados ODBC para especificar a instância usando o seguinte formato: servidor\instância_nomeada. Por padrão, o SQL Server Express é instalado em uma instância nomeada.
Execute a primeira listagem de código ( Transact-SQL) para criar o procedimento armazenado usado por este exemplo.
Compile a segunda listagem de código (C++) com odbc32.lib. Em seguida, execute o programa.
Execute a terceira listagem de código (Transact-SQL) para excluir o procedimento armazenado usado por este exemplo.
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