[unixODBC-dev] libodbcpsql seems seems sensitive to EOFs from Postgresql

Robert Kiesling kiesling at earthlink.net
Sun Jan 20 21:49:19 GMT 2008

> Robert Kiesling <kiesling at earthlink.net> writes:
> > The libodbcpsql driver seems sensitive to EOFs from Postgres, 8.2.6.
> > The fault seems to occur intermittently in SQLGetDiagRec, and causes
> > either unixODBC, version 2.1.12, or Perl, connected to unixODBC with
> > UnixODBC.pm, to segfault.
> > The error is: "LOG:  unexpected EOF on client connection" printed on the terminal,
> > then a segfault
> I think you've got the causality backward.  That log message is the
> server reporting that the client dropped the connection ungracefully.
> Can we see a gdb stack trace from the segfault?

I was able to duplicate the error with a test program.  Here is the
gdb output.

| Starting program: /home/rkiesling/test -P test.c -o test.i
| Failed to read a valid object file image from memory.
| [Thread debugging using libthread_db enabled]
| [New Thread -1210124608 (LWP 16408)]
| Connected !
| Error Select -2
| Program received signal SIGSEGV, Segmentation fault.
| [Switching to Thread -1210124608 (LWP 16408)]
| 0xb7f70725 in extract_sql_error_rec (head=0x804ac38, sqlstate=0x8049d18 "00000", 
|    rec_number=1, native_error=0x8049d14, message_text=0x8049c40 "", buffer_length=100, 
|    text_length=0x8049d08) at SQLGetDiagRec.c:440
|440                 as1 = (SQLCHAR*) unicode_to_ansi_alloc( ptr -> msg, SQL_NTS, __get_connection( head ));
| (gdb) backtrace
| #0  0xb7f70725 in extract_sql_error_rec (head=0x804ac38, sqlstate=0x8049d18 "00000", 
|    rec_number=1, native_error=0x8049d14, message_text=0x8049c40 "", buffer_length=100, 
|    text_length=0x8049d08) at SQLGetDiagRec.c:440
| #1  0xb7f70cc9 in SQLGetDiagRec (handle_type=2, handle=0x804a6c8, rec_number=1, 
|    sqlstate=0x8049d18 "00000", native=0x8049d14, message_text=0x8049c40 "", 
|    buffer_length=100, text_length_ptr=0x8049d08) at SQLGetDiagRec.c:663
| #2  0x08048882 in main (argc=5, argv=0xbfecb334) at test.c:70
| (gdb) 

Here is the test program:

#include <stdlib.h>
#include <stdio.h>
#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>

SQLHENV                  V_OD_Env;     // Handle ODBC environment              
long                     V_OD_erg;     // result of functions
SQLHDBC                  V_OD_hdbc;    // Handle connection

char                     V_OD_stat[10]; // Status SQL
SQLINTEGER               V_OD_err,V_OD_rowanz,V_OD_id;                
SQLSMALLINT              V_OD_mlen;
char             V_OD_msg[200],V_OD_buffer[200];

SQLHSTMT V_OD_hstmt;   // Handle for a statement
char V_OD_buffer[200];

int main (int argc, char **argv) {

        // 1. allocate Environment handle and register version
        if ((V_OD_erg != SQL_SUCCESS) && (V_OD_erg != SQL_SUCCESS_WITH_INFO))
                printf("Error AllocHandle\n");
        V_OD_erg=SQLSetEnvAttr(V_OD_Env, SQL_ATTR_ODBC_VERSION,
                               (void*)SQL_OV_ODBC2, 0);
        if ((V_OD_erg != SQL_SUCCESS) && (V_OD_erg != SQL_SUCCESS_WITH_INFO))
                printf("Error SetEnv\n");
                SQLFreeHandle(SQL_HANDLE_ENV, V_OD_Env);

        // 2. allocate connection handle, set timeout
        V_OD_erg = SQLAllocHandle(SQL_HANDLE_DBC, V_OD_Env, &V_OD_hdbc);
        if ((V_OD_erg != SQL_SUCCESS) && (V_OD_erg != SQL_SUCCESS_WITH_INFO))
                printf("Error AllocHDB %d\n",V_OD_erg);
                SQLFreeHandle(SQL_HANDLE_ENV, V_OD_Env);
        SQLSetConnectAttr(V_OD_hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)5, 0);

        // 3. Connect to the datasource "Gutenberg Catalog"
        V_OD_erg = SQLConnect(V_OD_hdbc, (SQLCHAR*) "Gutenberg Catalog", SQL_NTS,
                                     (SQLCHAR*) "postgres", SQL_NTS,
                                     (SQLCHAR*) "", SQL_NTS);
        if ((V_OD_erg != SQL_SUCCESS) && (V_OD_erg != SQL_SUCCESS_WITH_INFO))
                printf("Error SQLConnect %d\n",V_OD_erg);
                SQLGetDiagRec(SQL_HANDLE_DBC, V_OD_hdbc,1,
                              V_OD_stat, &V_OD_err,V_OD_msg,100,&V_OD_mlen);
                printf("%s (%d)\n",V_OD_msg,V_OD_err);
                SQLFreeHandle(SQL_HANDLE_ENV, V_OD_Env);
        printf("Connected !\n");

             "SELECT dtname,iduser FROM tkeyuser order by iduser",SQL_NTS);
 if ((V_OD_erg != SQL_SUCCESS) && (V_OD_erg != SQL_SUCCESS_WITH_INFO))       
     printf("Error Select %d\n",V_OD_erg);
     SQLGetDiagRec(SQL_HANDLE_DBC, V_OD_hdbc,1, V_OD_stat, &V_OD_err,
     printf("%s (%d)\n",V_OD_msg,V_OD_err);
     SQLFreeHandle(SQL_HANDLE_ENV, V_OD_Env);


> > This issue does not occur with the psqlODBC driver.  The operating system
> > is Debian GNU/Linux etch.
> Can't speak for Debian, but on Red Hat I routinely recommend using
> postgresql-odbc with unixODBC.  The libodbcpsql driver that comes with
> unixODBC is very old and seems unmaintained.  The same goes for
> mysql-connector-odbc versus the one in unixODBC.  I've actually
> considered removing these libraries from the unixODBC RPM to make
> people get the more up-to-date ones ...

Agreed - psqlODBC seems much more up-to-date.  I checked back through
the unixODBC versions, btw, and the signal(s) from Postgres is(are)
still catchable in unixODBC 2.1.10 from Perl with a signal handler.  I
don't think the error above is caused by a signal from the Postgres
domain socket optimizations, however.

psqlODBC should be less generic, though, if it watches signals from
Postgres that closely.

MyODBC only works up to MySQL 3.53 or so.  I've hacked at it for MySQL 4, 
although the older MySQLs don't build out of the box with newer versions 
of GCC either, so Connector/ODBC seems like it needs to be a requirement.
All of the MySQL releases work great for me if I can build them from the
source distros.

On an off-topic note, is there some reason why the dm_log_* functions 
are no longer exported?

Thanks again,


Ctalk Home Page: http://www.ctalklang.org/

More information about the unixODBC-dev mailing list