How to process ODBC errors (ODBC)

How to Install SQL Server 2000

How To

How to process ODBC errors (ODBC)

Two ODBC function calls can be used to retrieve ODBC messages: SQLGetDiagRec and SQLGetDiagField. To obtain primary ODBC-related information in the SQLState, pfNative, and ErrorMessage diagnostic fields, call SQLGetDiagRec until it returns SQL_NO_DATA. For each diagnostic record, SQLGetDiagField can be called to retrieve individual fields. All driver-specific fields must be retrieved using SQLGetDiagField.

SQLGetDiagRec and SQLGetDiagField are processed by ODBC Driver Manager, not an individual driver. ODBC Driver Manager does not cache driver-specific diagnostic fields until a successful connection has been made. Calling SQLGetDiagField for driver-specific diagnostic fields is not possible before a successful connection. This includes the ODBC connection commands, even if they return SQL_SUCCESS_WITH_INFO. Driver-specific diagnostic fields will not be available until the next ODBC function call.

Examples

The following example shows a simple error handler that calls SQLGetDiagRec for the standard ODBC information. It then tests for a valid connection, and if there is, it calls SQLGetDiagField for the Microsoft® SQL Server™ ODBC driver-specific diagnostic fields.

// Example of SQL Server ODBC driver-specific options
// on SQLGetDiagField.
//
// This application assumes the existence of the following
// stored procedure:
//
// CREATE PROCEDURE BadOne AS SELECT * FROM NotThere
//
// where no object named NotThere exists.

#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;
char         logstring[MAXBUFLEN] = "";

void      ProcessLogMessages(SQLSMALLINT plm_handle_type,
                     SQLHANDLE plm_handle, char *logstring,
                     int ConnInd);

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");
      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");
      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");
      return(9);
   }
   retcode = SQLConnect(hdbc1, "MyDSN", SQL_NTS,
      "sa", SQL_NTS, "MyPassWord", SQL_NTS);
   if ( (retcode != SQL_SUCCESS) &&
        (retcode != SQL_SUCCESS_WITH_INFO) ) {
         ProcessLogMessages(SQL_HANDLE_DBC, hdbc1,
               "SQLConnect() Failed\n\n", FALSE);
         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);
         return(9);
   }
   retcode = SQLExecDirect(hstmt1, "exec BadOne", SQL_NTS);
   if ( (retcode != SQL_SUCCESS) &&
        (retcode != SQL_SUCCESS_WITH_INFO) ) {
         ProcessLogMessages(SQL_HANDLE_STMT, hstmt1,
                  "SQLExecute() Failed\n\n", TRUE);
         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);
   return(0);
}

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];

   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.
   } // End while.
}

See Also

Handling Errors and Messages

SQLGetDiagField

Diagnostic Records and Fields