Skip to Content.
Sympa Menu

freetds - [freetds] The FreeTDS's current odbc driver and the iodbc can't work together on solaris, the reason and possible solution.

freetds AT lists.ibiblio.org

Subject: FreeTDS Development Group

List archive

Chronological Thread  
  • From: "Ou Liu" <ou AT qbt.com>
  • To: <freetds AT lists.ibiblio.org>
  • Subject: [freetds] The FreeTDS's current odbc driver and the iodbc can't work together on solaris, the reason and possible solution.
  • Date: Wed, 11 Dec 2002 16:45:25 -0500

Hi, everyone
I thought there may be some "bugs" in both iodbc and FreeTDS. (In
fact, I
didn't take them bugs)

Ok, once again let's start from my environment:

Environment and build setting
----------------------------------------------------------------------------
--------------------------------------
Hardware: SPARC (Sun Blade 100)

OS: Solaris 8

Compiler: gcc (2.95 or lower, I don't know, maybe it is the
problem)

Compiling Setting for the iODBC:
configure --disable-gui --disable-gtktest --prefix=/usr/local/iodbc
AR=/opt/sfw/sparc-sun-solaris2.8/bin/ar
RANLIB=/opt/sfw/sparc-sun-solaris2.8/bin/ranlib CC=/opt/sfw/bin/gcc

Compiling Setting for the freetds:

configure --with-iodbc=/usr/local/iodbc --prefix=/usr/local/freetds --with-t
dsver=7.0 AR=/opt/sfw/sparc-sun-solaris2.8/bin/ar
RANLIB=/opt/sfw/sparc-sun-solaris2.8/bin/ranlib CC=/opt/sfw/bin/gcc
----------------------------------------------------------------------------
--------------------------------------

The problems are:
1. If I compile the iODBC with --disable-odbc3, then compilation of
iODBC
will not work because some errors I will explain.
2. If I compile the iODBC without --disable-odbc3, then both
compilation
will succeed but they can't work together, which I will explain too.

Explaination:
----------------------------------------------------------------------------
--------------------------------------
1. Why I can't compile the iODBC with --disable-odbc3 ?

Because in the /iODBCHOME/iodbcinst/ directory there is a file namely
SQLConfigDataSource.c and in this file we have a function
"SQLConfigDataSource()" which used a definition ODBC_USER_DSN and many other
definitions which is located in the iodbcinst.h (in /iODBCHOME/include). But
those definitions will be exposed only when ODBC Version is greater than 3,
which means I can't use the --disable-odbc3 option.

The definition in iodbcinst.h is right, since by checking Microsoft's
odbcinst.h you can see that the Microsoft define the const like:
#if (ODBCVER >= 0x0300)
#define ODBC_BOTH_DSN 0
#define ODBC_USER_DSN 1
#define ODBC_SYSTEM_DSN 2
#endif /* ODBCVER >= 0x0300 */

Seems to me it is the problme of the code. The coder seems to forget
add
#if ... into the code. There are many such errors.

2. Why I can't put the FreeTDS's ODBC driver and iODBC driver manager
work
together when I didn't set the option --disable-odbc3 (which makes the
compilation of iODBC successful) ?

In fact, both the iodbc's test tool 'odbctest' and the FreeTDS's
unittest
tool of ODBC drive 'connect' can't work. I will explain one by one:

(1) why FreeTDS's unittest tool 'connect' can't work:

A. Because the connect.c will call the iODBC's SQLConnect located
in the
libiodbc.so.2 first (thanks to freddy taught me to use ldd), and the iODBC's
SQLConnect will load the libtdsodbc.so by calling a function of the iODBC,
namely _iodbcdm_driverload, the problem is in this function and the current
version of FreeTDS's odbc driver:

code from the _iodbcdm_driverload :
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++
/* call driver's SQLAllocHandle() or SQLAllocEnv() */

#if (ODBCVER >= 0x0300)
hproc = _iodbcdm_getproc (pdbc, en_AllocHandle);

if (hproc)
{
penv->dodbc_ver = SQL_OV_ODBC3;
CALL_DRIVER (hdbc, genv, retcode, hproc, en_AllocHandle,
(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(penv->dhenv)));
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
{ /* this is an ODBC3 driver - introduce the
app's requested version */
hproc = _iodbcdm_getproc (pdbc, en_SetEnvAttr);
if (hproc != SQL_NULL_HPROC)
{
CALL_DRIVER (hdbc, genv, retcode, hproc, en_SetStmtAttr,
(penv->dhenv, SQL_ATTR_ODBC_VERSION,
genv->odbc_ver, 0));
}
}
}
else /* try driver's SQLAllocEnv() */
#endif
{
hproc = _iodbcdm_getproc (pdbc, en_AllocEnv);

if (hproc == SQL_NULL_HPROC)
{
sqlstat = en_IM004;
}
else
{
#if (ODBCVER >= 0x0300)
penv->dodbc_ver = SQL_OV_ODBC2;
#endif
CALL_DRIVER (hdbc, genv, retcode, hproc,
en_AllocEnv, (&(penv->dhenv)));
}
}

if (retcode == SQL_ERROR)
{
sqlstat = en_IM004;
}

if (sqlstat != en_00000)
{
_iodbcdm_dllclose (hdll);
MEM_FREE (penv);
PUSHSQLERR (pdbc->herr, en_IM004);

return SQL_ERROR;
}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++
Now the problem is :
(i). The en_SetStmtAttr should be en_SetEnvAttr, but it doesn't matter
since it only used in the trace file. (thanks to Patrick for explaining to
me that).
(ii). The FreeTDS's driver do have a function SQLSetEnvAttr but it
didn't
implemented and just simply return a SQL_FAILED, now you can see it will
force the whole function return an error.
(iii). Patrick help me solved this problem by set the retcode to
SQL_SUCCESS after the call to SQLSetEnvAttr, however it is not enough since
by doing that we skip the important initialization on the Environment. So I
add few lines after the call to the SQLSetEnvAttr. I add after

CALL_DRIVER (hdbc, genv, retcode, hproc, en_SetStmtAttr,
(penv->dhenv, SQL_ATTR_ODBC_VERSION,
genv->odbc_ver, 0));

following lines:

if(retcode != SQL_SUCCESS)
{ /* It is somewhat an odbc driver of version 2.5, we should call
SQLAllocEnv instead */
hproc = _iodbcdm_getproc (pdbc, en_AllocEnv);
if(hproc == SQL_NULL_HPROC)
{
sqlstat = en_IM004;
}
else
{
penv->dodbc_ver = SQL_OV_ODBC2;
CALL_DRIVER (hdbc, genv, retcode, hproc,
en_AllocEnv, (&(penv->dhenv)));
}
}
Now this problem is solved, but you will see such kind of problem
are everywhere in the iodbc and FreeTDS's odbc driver.

B. After I fixed that _iodbcdm_driverload, it will return a
SQL_SUCCESS_WITH_INFO instead of the SQL_SUCESS, it is because the
_iodbcdm_driverload want to use SQLSetConnectOption() of FreeTDS's odbc
driver to set a log-in timeout. Unfornuately it is not supported in the
FreeTDS's odbc driver and will return an SQL_FAILED to the
_iodbcdm_driverload. When the _iodbcdm_driverload receive this code it will
return SQL_SUCCESS_WITH_INFO to the caller notifying that although the
connection has been set up, the endeavour to set the log-in timeout is
failed.
However the connect.c of the unittest tool of the FreeTDS's odbc
driver didn't check that, it will abort immediately if the return of the
SQLConnect() (it is a call to the iodbc and which will call the
_iodbcdm_driver) is not SQL_SUCCESS, it didn't check if the result is
SQL_SUCCESS_WITH_INFO! I suggest we can design a macro SUCCESSED instead of
comaring the return code straightly with the SQL_SUCCESS.
After I fixed this, the first two connect test will succeed, however
the last one still fail, but I don't care any more.
C. When I use the Makefile to make connect by dong "make connect", there
is an error in the Makefile of connect:
it use the -lodbc option, but when dealing with iODBC I thought it
should
be -liodbc, otherwize the building will crash.

(2) Why the odbctest didn't work fully?
After I do the fixation above, I do make the odbctest work. It can
connect
with the MSSQL 2000 server on another Windows2000 machine. But when I try to
fetch some data from the server by doing:

SQL> use test;
SQL> select * from foo;

The call "select * from foo" will not succeed because it will call the
iODBC's SQLFetch() function in the fetch.c and this function try to use
SQLExtendedFetch to simulate the SQLFetch, once again the problem is that
once the driver manager found there is a handle to the function
SQLExtendedFetch in the driver, it never check again that the
SQLExtenedFetch is really implemented or not(Unfornuately it is not).

code from SQLFetch:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++
#if (ODBCVER >= 0x0300)
if (((ENV_t FAR *) ((DBC_t FAR *) pstmt->hdbc)->henv)->dodbc_ver ==
SQL_OV_ODBC2
&& ((GENV_t FAR *) ((DBC_t FAR *) pstmt->hdbc)->genv)->odbc_ver ==
SQL_OV_ODBC3)
{
/*
* Try to map SQLFetch to SQLExtendedFetch for ODBC3 app calling
* ODBC2 driver
*
* The rows_status_ptr must not be null because the SQLExtendedFetch
* requires it
*/
hproc = _iodbcdm_getproc (pstmt->hdbc, en_ExtendedFetch);
if (hproc)
{
CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc, en_ExtendedFetch,
(pstmt->dhstmt, SQL_FETCH_NEXT, 0, pstmt->rows_fetched_ptr,
pstmt->row_status_ptr));
}
}
#endif
if (hproc == SQL_NULL_HPROC)
{
hproc = _iodbcdm_getproc (pstmt->hdbc, en_Fetch);

if (hproc == SQL_NULL_HPROC)
{
PUSHSQLERR (pstmt->herr, en_IM001);

LEAVE_STMT (pstmt, SQL_ERROR);
}

CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc, en_Fetch,
(pstmt->dhstmt));
}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++
Here once the call to the SQLExtenedFetch is failed, the driver manager
will no more try to use SQLFetch instead but straightly return back an
error.
I didn't fix this problem yet, because I thought such problem will be
everywhere until you good guys implement all the odbc 3 driver's functions.
By the way, there is an small bug in the threadsafe.c 's function
tds_get_homedir(void):

-----------------------------------------------------------
getpwuid_r(getuid(), &bpw, buf, sizeof(buf), pw);
-----------------------------------------------------------

On the Linux it is right, but on solaris the getpwuid_r still only
take
four parameters, so it should be:
-----------------------------------------------------------
pw = getpwuid_r(getuid(), &bpw, buf, sizeof(buf) );
-----------------------------------------------------------

But I gladly see that someone already take this problem out and freddy
fixed it already. ( I also consult Patrick who said there will be some
fixation on the configuration file)


In the end, I have four possible solution:
(i) Hope you guys finished all those unimplemented functions in one
day or
two, which I thought is impossible. (^_^)
(ii) Hope Patrick will solve this problem by modify the driver
manager, and
at everywhere check whether a deprecated version is usable once the call to
the current version is failed. Which is also impossible I am afraid, (^_^)
(iii) Try to compile the iODBC use the option --disable-odbc3, and to
do
that I should check out all the place will make the building crash and fix
them, which I am afraid is also impossible. (^_^)
(iv) Go back to your old version of FreeTDS, which I am trying to do,
but I
can't download the FreeTDS0.60 on your website today, I don't know why, and
I don't know how to download it from CVS although I can view it. This I
thought is the most practical way to solve my problem.


Is there any suggestions?

Thank you all
Ou
----------------------------------------------------------------------------
--------------------------------------




  • [freetds] The FreeTDS's current odbc driver and the iodbc can't work together on solaris, the reason and possible solution., Ou Liu, 12/11/2002

Archive powered by MHonArc 2.6.24.

Top of Page