ODBC diagnostics and error status codes
Contents
- Introduction
- ODBC status returns
- Obtaining diagnostics
- Diagnostic fields
- Example diagnostic messages
- Appendix A: ODBC status return codes
- Appendix B: ODBC 2 to ODBC 3
SQLSTATE
mappings
Introduction
This article describes how to retrieve and interpret ODBC diagnostic information. This guide also links to a page that provides a complete list of SQLSTATE
status return codes and the ODBC functions that return them.
ODBC status returns
SQLGetDiagRec
and SQLGetDiagField
return SQLSTATE
values. SQLSTATE
values are strings that contain five characters. The appendices in this article list the SQLSTATE
values that an ODBC driver can return for SQLGetDiagRec
.
The character string value returned in an SQLSTATE
consists of a two-character class value followed by a three-character subclass value. A class value of 01
indicates a warning and is accompanied by a return code of SQL_SUCCESS_WITH_INFO
. Class values other than 01
, except for the class IM
, indicate an error and are accompanied by a return value of SQL_ERROR
. The class IM
is specific to warnings and errors that derive from the implementation of ODBC itself. The subclass value 000
in any class indicates that there is no subclass for that SQLSTATE
. The assignment of class and subclass values is defined by SQL-92.
Note Although the successful execution of a function is normally indicated by a return value of SQL_SUCCESS
, the SQLSTATE
00000
also indicates success.
All ODBC APIs return a status value that you can use to check whether the function succeeded. In C, you can test the return value from an ODBC function using the SQL_SUCCEEDED
macro. For example:
SQLRETURN fsts; /* Assume for this example the environment has already been allocated */ SQLHENV envh; SQLHDBC dbch; fsts = SQLAllocHandle(SQL_HANDLE_DBC, envh, &dbch); if (!SQL_SUCCEEDED(fsts)) { /* an error occurred allocating the database handle */ } else { /* Database handle allocated OK */ }
The SQL_SUCCEEDED
macro is defined as:
#define SQL_SUCCEEDED(rc) (((rc)&(~1))==0)
Virtually all ODBC functions can return two values that indicate success:
SQL_SUCCESS
SQL_SUCCESS_WITH_INFO
Both of these return values cause the SQL_SUCCEEDED
macro to result in 1
.
If a function returns SQL_SUCCESS_WITH_INFO
, it means that the call succeeded but an informational message was produced. For example, with some ODBC drivers you might set the cursor type, prepare a statement, and then execute it. When you call SQLExecute
, the statement is acted upon, but the ODBC driver might change the cursor type to something else. In this case, SQLExecute
would return SQL_SUCCESS_WITH_INFO
and the ODBC driver would add a diagnostic indicating the cursor type had been changed.
You should note that a few ODBC functions return a status that fails the SQL_SUCCEEDED
macro, but does not indicate an error as such. For example, SQLFetch
can return SQL_NO_DATA
indicating that there are no further rows in the result set. This is not necessarily an error.
Obtaining diagnostics
When an ODBC function returns an error or SQL_SUCCESS_WITH_INFO
, the ODBC driver associates a diagnostic with the handle used in the ODBC call. You can obtain the diagnostic to find out what failed by calling SQLGetDiagRec
with the handle you used in the ODBC call that failed.
The ODBC driver may associate multiple diagnostic records with a handle.
You can call SQLGetDiagField
and request the SQL_DIAG_NUMBER
attribute to find out how many diagnostics exist. Alternatively, as diagnostic records start at 1
, you can repeatedly call SQLGetDiagRec
asking for record 1, then 2 (and so on) until SQLGetDiagRec
returns SQL_NO_DATA
.
As an example, the following C function takes a function name string, handle type and handle and retrieves all the diagnostics associated with that handle.
void extract_error( char *fn, SQLHANDLE handle, SQLSMALLINT type) { SQLINTEGER i = 0; SQLINTEGER native; SQLCHAR state[ 7 ]; SQLCHAR text[256]; SQLSMALLINT len; SQLRETURN ret; fprintf(stderr, "\n" "The ODBC driver reported the following diagnostics whilst running " "%s\n\n", fn); do { ret = SQLGetDiagRec(type, handle, ++i, state, &native, text, sizeof(text), &len ); if (SQL_SUCCEEDED(ret)) printf("%s:%ld:%ld:%s\n", state, i, native, text); } while( ret == SQL_SUCCESS ); }
Using the example above, which attempts to allocate a database handle, you could use extract_error
as follows:
SQLRETURN fsts; /* Assume for this example the environment has already been allocated */ SQLHENV envh; SQLHDBC dbch; fsts = SQLAllocHandle(SQL_HANDLE_DBC, envh, &dbch); if (!SQL_SUCCEEDED(fsts)) { extract_error("SQLAllocHandle for dbc", envh, SQL_HANDLE_ENV); exit(1); } else { /* Database handle allocated OK */ }
ODBC 2.0 applications use SQLError
instead of SQLGetDiagRec
.
Diagnostic fields
When you call SQLGetDiagRec
you can retrieve three diagnostic fields:
- State
- Native error code
- Message text
The state is a five character SQLSTATE
code. The first two characters indicate the class and the next three indicate the subclass. SQLSTATE
s provide detailed information about the cause of a warning or error. You can look states up in Appendix A.
The native error code is a code specific to the data source. This number is often extremely useful to ODBC driver developers in locating an internal error or state. If you're reporting a bug in an ODBC driver for which you obtained an error you should always quote the ODBC function called, the error text, and this native number.
The message text is the text of the diagnostic. This string takes one of two forms:
For errors and warnings that do not occur in a data source the format:
[vendor-identifier][ODBC-component-identifier]component-supplied-text
otherwise:
[vendor-identifier][ODBC-component-identifier][data-source-identifer] data-source-supplied-text
Example diagnostic messages
You can use the message text string to identify which piece of software reported the error. For example, here are some message texts and error conditions generated using the Easysoft ODBC-ODBC Bridge with Microsoft SQL Server:
[Easysoft ODBC (Client)]Invalid authorization specification
This error was produced when the connection attempt was refused because the LogonUser
and LogonAuth
attributes were invalid. The ODBC-ODBC Bridge alone was involved in this process.
[Easysoft ODBC (Server)][Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified.
This error was produced by the Microsoft ODBC Driver Manager on the ODBC-ODBC Bridge server machine, because the TargetDSN
attribute specified an ODBC data source that didn't exist. The last item in square brackets was ODBC Driver Manager
and therefore that's the component that generated the error text. As the text is prefixed with [Easysoft ODBC (Server)]
, you know that it was the ODBC Driver Manager on the server machine.
[Easysoft ODBC (Server)][Microsoft][ODBC SQL Server Driver][SQL Server] Login failed for user 'demo'.
This error was produced when the TargetUser
and TargetAuth
specified with the ODBC-ODBC Bridge client was passed through to the DBMS, which refused the connection. The last item in square brackets was SQL Server
and so you know that SQL Server turned down the connection attempt.
Appendix A: ODBC status return codes
This appendix lists all ODBC status return codes.
The list includes error messages and the functions that can return the status code complete with a brief description.
Appendix B: ODBC 2.x to ODBC 3.x SQLSTATE
mappings
This appendix lists ODBC 2.x to ODBC 3.x SQLSTATE
mappings.