Partilhar via


Processar erros ODBC (ODBC)

É possível usar duas chamadas de função ODBC para recuperar mensagens ODBC: 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ósticos específicos do driver ODBC do SQL Server. Essa amostra não tem suporte no IA64.

Este exemplo foi desenvolvido para o ODBC versão 3.0 ou posterior.

Observação sobre segurançaObservação sobre segurança

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 na página inicial de Microsoft SQL Server Samples and Community Projects (em inglês)). Essa fonte de dados deve ser baseada no driver ODBC que é fornecido pelo sistema operacional (o nome do driver é "SQL Server"). Se você for 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.

Esse aplicativo 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 com 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 AdventureWorks
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 AdventureWorks
DROP PROCEDURE BadOne
GO

Consulte também

Outros recursos

Tópicos de instruções sobre ODBC