Error handling in ODBC

Errors in ODBC are reported using the return value from each of the ODBC function calls and either the SQLError function or the SQLGetDiagRec function. The SQLError function was used in ODBC versions up to, but not including, version 3. As of version 3 the SQLError function has been deprecated and replaced by the SQLGetDiagRec function.

Every ODBC function returns a SQLRETURN, which is one of the following status codes:

Status code Description
SQL_SUCCESS No error.
SQL_SUCCESS_WITH_INFO

The function completed, but a call to SQLError will indicate a warning.

The most common case for this status is that a value being returned is too long for the buffer provided by the application.

SQL_ERROR The function did not complete because of an error. Call SQLError to get more information about the problem.
SQL_INVALID_HANDLE

An invalid environment, connection, or statement handle was passed as a parameter.

This often happens if a handle is used after it has been freed, or if the handle is the null pointer.

SQL_NO_DATA_FOUND

There is no information available.

The most common use for this status is when fetching from a cursor; it indicates that there are no more rows in the cursor.

SQL_NEED_DATA

Data is needed for a parameter.

This is an advanced feature described in the ODBC SDK documentation under SQLParamData and SQLPutData.

Every environment, connection, and statement handle can have one or more errors or warnings associated with it. Each call to SQLError or SQLGetDiagRec returns the information for one error and removes the information for that error. If you do not call SQLError or SQLGetDiagRec to remove all errors, the errors are removed on the next function call that passes the same handle as a parameter.

Each call to SQLError passes three handles for an environment, connection, and statement. The first call uses SQL_NULL_HSTMT to get the error associated with a connection. Similarly, a call with both SQL_NULL_DBC and SQL_NULL_HSTMT get any error associated with the environment handle.

Each call to SQLGetDiagRec can pass either an environment, connection or statement handle. The first call passes in a handle of type SQL_HANDLE_DBC to get the error associated with a connection. The second call passes in a handle of type SQL_HANDLE_STMT to get the error associated with the statement that was just executed.

SQLError and SQLGetDiagRec return SQL_SUCCESS if there is an error to report (not SQL_ERROR), and SQL_NO_DATA_FOUND if there are no more errors to report.

Example 1

The following code fragment uses SQLError and return codes:

SQLRETURN rc;
SQLHDBC dbc;
SQLHSTMT stmt;
UCHAR errmsg[100];

rc = SQLAllocHandle( SQL_HANDLE_STMT, dbc, &stmt ); 
if( rc == SQL_ERROR )
{
   SQLError( env, dbc, SQL_NULL_HSTMT, NULL, NULL,
         errmsg, sizeof(errmsg), NULL );
   print_error( "Allocation failed", errmsg );
   return;
}

/* Delete items for order 2015 */
rc = SQLExecDirect( stmt,
       "DELETE FROM SalesOrderItems WHERE ID=2015",
       SQL_NTS ); 
if( rc == SQL_ERROR ) 
{
   SQLError( env, dbc, stmt, NULL, NULL,
            errmsg, sizeof(errmsg), NULL );
   print_error( "Failed to delete items", errmsg );
   return;
}

Example 2

The following code fragment uses SQLGetDiagRec and return codes:

SQLRETURN rc;
SQLHDBC dbc;
SQLHSTMT stmt;
SQLSMALLINT errmsglen;
SQLINTEGER errnative;
SQLCHAR errmsg[255];
SQLCHAR errstate[5]; 

rc = SQLAllocHandle( SQL_HANDLE_STMT, dbc, &stmt );
if( rc == SQL_ERROR )
{
   SQLGetDiagRec( SQL_HANDLE_DBC, dbc, 1, errstate,
       &errnative, errmsg, sizeof(errmsg), &errmsglen );
   print_error( "Allocation failed", errstate, errnative, errmsg );
   return;
}

rc = SQLExecDirect( stmt,
       "DELETE FROM SalesOrderItems WHERE ID=2015",
       SQL_NTS ); 
if( rc == SQL_ERROR ) 
{
   SQLGetDiagRec( SQL_HANDLE_STMT, stmt, 1, errstate,
       &errnative, errmsg, sizeof(errmsg), &errmsglen );
   print_error( "Failed to delete items", errstate, errnative, errmsg );
   return;
}