Building DBD::ODBC against unixODBC on 64 bit platforms

A word of warning. The build process for DBD::ODBC against unixODBC on 64 bit platforms may not produce a workable solution perhaps even segfaulting. The short reason is that few Linux distributions/packages of unixODBC are up to date and few distribute unixODBC's odbc_config which DBD::ODBC needs to ascertain the compiler defines required to build a DBI driver which matches unixODBC. The long answer which which includes a workaround follows.

Some background:

As many of you may know MS invented ODBC and then I believe handed it over to X/Open. However, since then they have continued making changes to the API. Before Windows 64 bit operating systems many ODBC APIs were documented as taking or returning 32 bits values (and I mean that, not int or long but documented as a 32 bit value which is strange for a C API). When Windows 64 came along some APIs were changed to take an SQLLEN/SQLULEN or a pointer to a SQLLEN/SQLULEN and an SQLLEN/SQLULEN was defined as 32 bits on 32 bit operating systems and 64 bits on 64 bit operating systems.

unixODBC and many ODBC drivers who were ahead of MS and building drivers and driver managers for 64bit platforms could not know what MS were going to do and they did not all make the same choice. Most stuck with the API as it was which said 32 bit values. When MS changed ODBC to introduce SQLLEN/SQLULEN it left some driver writers with a problem and some had to produce 2 versions of their 64bit drivers - one using 32bit values for some ODBC API parameters and one using 64bit values as there were apps out there doing both.

These days unixODBC supports SQLLEN/SQLULEN and most drivers do and unixODBC builds out the box with a 64bit SQLLEN/SQLULEN value. However, this is ascertained at configure time and the header files which go with unixODBC define SQLLEN/SQLULEN as 32bit or 64bit depending on whether SIZEOF_LONG_INT is 32 or 64. DBD::ODBC looks for unixODBC's odbc_config program which can be used to return the cc flags used to build unixODBC and one of those flags is -DSIZEOF_LONG_INT=64. When DBD::ODBC finds odbc_config it can add the right flags to the compiler when building DBD::ODBC. When DBD::ODBC cannot find odbc_config (and it goes out of its way to find it) it cannot know what to add to the compile line so adds nothing. The result is that if you build DBD::ODBC on a 64bit platform against unixODBC and odbc_config is not found SQLLEN/SQLULEN will be 32 bits in size (incorrectly most of the time) and then APIs like SQLRowCount which is passed a pointer to a SQLLEN will pass a pointer to 4 bytes of space instead of 8 - thus corrupting the stack.

Now, whether your app (or DBD::ODBC or Perl) will segfault or when it will segfault is just pot luck. It is not a driver bug but a bug in the building of DBD::ODBC in a way incompatible with unixODBC. To correct this you need to set:

$opts{DEFINE} .= ' -DSIZEOF_LONG_INT=8;

to the Makefile.PL around line 225 outside the if for $opt_u.

As a side note to anyone looking after packages for Linux especially like Ubuntu, Debian etc. Please, please upgrade unixODBC in your package system to a newer version AND include odbc_config.

I am sorry this has caused you some problems. I will try and change DBD::ODBC to issue a warning on 64 bit platforms if odbc_config is not found but as few people pay much attention to the warnings I'm not sure what good it will do.