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 to see if there is 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);

    }

  

    // Let ODBC know 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  

  


(c) 1988-98 Microsoft Corporation. All Rights Reserved.