PATCH: ODBC application discarding sqlstate in get_diagnos function

Andrew Thompson <>
Fri Oct 9 19:47:43 CEST 2009


I've been using the ODBC application against a unixodbc/mysql setup for
a while now and its been bothering me that ANY SQL error always returns
{port_exit,could_not_access_column_count} from the erlang side. I
decided to dig into the code and figure out why and this is what I

In the get_diagnos function of odbcserver.c every time SQLGetDiagRec is
called diagnos.sqlState is passed in as the target to write the returned
SQLSTATE into. However, when you've run out of diagnostic information
and SQLGetDiagRec() returns something other than SQL_SUCCESS, the value
of diagnos.sqlState *still* gets changed (at least in my case) to 00000,
which is, of course, the INFO SQLSTATE. This causes the check in
db_query against INFO to succeed when it should be failing and since in
my case the error message didn't begin with 'error' it falls through
encode_result which is where the EXIT_COLS comes in. Attached is a patch
to resolve this problem by only updating diagnos.sqlState when
SQLGetDiagRec returns success.

I don't know if all ODBC implementations behave this way, but I'd assume
that the SQLSTATE from a failed SQLGetDiagRec can safely be ignored in
all cases.


-------------- next part --------------
--- c_src/odbcserver.c.orig	2009-10-09 13:11:01.000000000 -0400
+++ c_src/odbcserver.c	2009-10-09 13:20:21.000000000 -0400
@@ -2451,6 +2451,7 @@
     SQLSMALLINT errmsg_buffer_size, record_nr, errmsg_size;
     int acc_errmsg_size;
     byte *current_errmsg_pos;
+    SQLCHAR current_sql_state[SQL_STATE_SIZE];
     diagnos.error_msg[0] = 0;
@@ -2463,7 +2464,7 @@
     /* Foreach diagnostic record in the current set of diagnostic records
        the error message is obtained */
     for(record_nr = 1; ;record_nr++) {    
-	if(SQLGetDiagRec(handleType, handle, record_nr, diagnos.sqlState,
+	if(SQLGetDiagRec(handleType, handle, record_nr, current_sql_state,
 			 &nativeError, current_errmsg_pos,
 			 (SQLSMALLINT)errmsg_buffer_size, &errmsg_size)
 	   != SQL_SUCCESS) {
@@ -2471,6 +2472,9 @@
 	} else {
+	    /* update the sqlstate in the diagnos record, because the SQLGetDiagRec
+	       call succeeded */
+	    memcpy(diagnos.sqlState, current_sql_state, SQL_STATE_SIZE);
 	    errmsg_buffer_size = errmsg_buffer_size - errmsg_size;
 	    acc_errmsg_size = acc_errmsg_size + errmsg_size;
 	    current_errmsg_pos = current_errmsg_pos + errmsg_size;

More information about the erlang-patches mailing list