[freetds] FreeTDS, C++, and Exceptions

Lenon Kitchens lenonk at sanctuary.org
Sat Jun 17 03:55:37 EDT 2006


Hi folks,

I have a problem with FreeTDS that I was hoping someone could help me 
solve.  I'm a developer for a company that deals in network management 
software.  Since basically all of our applications need to have the 
ability to talk to one or more of SQLServer, Oracle, SQLite, Sybase,  I 
have written a C++ library to provide a common interface to all of these 
APIs.

It wasn't until recently that I noticed a problem with the FreeTDS part 
of my implementation.  I have installed error and message handlers using 
dberrhandle() and dbmsghandle().  At the end of each of these functions, 
I throw an exception like so:

throw DBLibException(EGENERAL_EXCEPTION, err.str());

The "err" string is obviously filled out during the function.  The 
problem is that for some reason, this exception goes completely uncaught 
and results in terminate() being called.

Here's the output of a test program:

[lenon at atllnxdev01 libcentivia]$ ./test
checking tdsport
terminate called after throwing an instance of 'DBLibException'
Aborted

Here's the test program itself:

#include <stdio.h>

int main(void) {
   DBConnection *SQLServerConn;
   try {
       SQLServerConn = DBConnection::buildConnection(SQLServer, "10.0.0.0",
               "username", "password");
       SQLServerConn->connect("database");

       // Foo is obviously an invalid table name which will cause an 
exception
       // to be thrown.
       SQLServerConn->execute("select * from foo");
   }
   catch (DBLibException &e) {
       cout << "DBLib Exception: " << e.getErrInfo() << endl;
       return -1;
   }
}


If I throw this exact same exception immediately before the call to 
dbsqlexec(), it works fine.

Here are the two installed handlers:

int
sybErrHandler(DBPROCESS *dbProc, int severity, int dbErr, int osErr,
       char *dbErrStr, char *osErrStr) {
   string err;
   // It's OK to end up here in response to a dbconvert() that
   // resulted in overflow, so don't exit in that case.
   if (dbErr == SYBEICONVI)
       return 0;

   /*
   * For server messages, cancel the query and rely on the
   * message handler to spew the appropriate error messages out.
   */
   if (dbErr == SYBESMSG)
       return INT_CANCEL;

   err = "\nDBLIB ERROR: [" + string(dbErrStr) + "]";

   if (osErr != DBNOERR)
       err += "\nOS ERROR: [" + string(osErrStr) + "]";

   throw DBLibException(EGENERAL_EXCEPTION, err);
}

int
sybMsgHandler(DBPROCESS *dbProc, DBINT msgNo, int msgState,
       int severity, char *msgText, char *srvName, char *procName, int 
line) {

   if (msgNo == 5701 || msgNo == 5703 || msgNo == 5704)
       return (INT_CONTINUE);

   stringstream err;
   err << "\nDBLIB MESSAGE: [msgno: " << msgNo <<
          ", level: " << severity << ", State: " << msgState << "]";
   if (*srvName)
       err << "\nSERVER: [" << srvName << "]";
   if (*procName)
       err << "\nPROCEDURE: [" << procName << "]";
   if (line > 0)
       err << "\nLINE: [" << line << "]";

   err << "\nMESSAGE: " << msgText;

   throw DBLibException(EGENERAL_EXCEPTION, err.str());
}


Any help will be greatly appreciated.

Thanks!

Lenon Kitchens


More information about the FreeTDS mailing list