[Mono-dev] Show-stopper bug in libodbc.cs
quandary
quandary82 at hailmail.net
Mon Jan 16 23:21:33 UTC 2012
Hi,
I've ripped System.Data.Odbc out of mcs/class, to hold an extended
little debug-session last Sunday.
Overall, the good message is, that so far, it seems to be working
perfectly with Sybase, which is strange, but all I need at the moment.
I was also reattempting to read some tables in NorthWind.mdb (the
MS-Access example file), to test whether Access over ODBC now works.
It's already much better than last time, but unsurprisingly, I've still
found a few show-stopping bugs, mainly in
System.Data/System.Data.Odbc/libodbc.cs
You have this (in 6 overloads):
[DllImport ("odbc32.dll", CharSet = CharSet.Unicode)]
internal static extern OdbcReturn SQLGetData (
IntPtr StatementHandle,
ushort ColumnNumber,
SQL_C_TYPE TargetType,System.Int64
byte[] TargetPtr,
int BufferLen,
ref int Len);
But MSDN and the header-file in /usr/include defines SQLGetData like this:
SQLRETURN SQLGetData(
SQLHSTMT StatementHandle,
SQLUSMALLINT Col_or_Param_Num,
SQLSMALLINT TargetType,
SQLPOINTER TargetValuePtr,
SQLLEN BufferLength,
SQLLEN * StrLen_or_IndPtr);
Note that SQLLEN thing there:
typedef long SQLLEN
And while
sizeof(long) = 4 = sizeof(int) on x86-32 and x86-64 Windows, as well as
x86-32 Linux
for x86-64 on Linux sizeof(long) = 8 == != sizeof(int) = 4 on x86-64
Linux
I got all kinds of wired error messages with a definition like that.
(credits for discovering the cause go to g++ warnings)
I fixed it for my system by replacing int with System.Int64, which works
fine FOR ME, since I only need to care about my system.
You should probably fix it by using IntPtr, but I don't know about
64-bit Windows.
[DllImport ("odbc32.dll", CharSet = CharSet.Unicode)]
internal static extern OdbcReturn SQLGetData (
IntPtr StatementHandle,
ushort ColumnNumber,
SQL_C_TYPE TargetType,
byte[] TargetPtr,
int BufferLen,
ref int Len);
Then there is a "bug" in Function GetValue in OdbcDataReader.cs
Overall, case OdbcType.VarChar seems to be the troublechild.
I did a
"SELECT CompanyName, City From Customers"; // Access, file NorthWind.mdb
The result is really an infinite do-while loop
(i fixed it by just adding a break statement - no idea how correct that
is, but I see no reason why this is in a loop at all)
OdbcDataReader --> GetValue --> case OdbcType.VarChar
do {
ret = libodbc.SQLGetData (hstmt, ColIndex,
col.SqlCType, buffer, bufsize, ref outsize);
if (ret == OdbcReturn.Error)
break;
// Fix for strance ODBC drivers (like psqlODBC)
if (ret == OdbcReturn.Success && outsize==-1)
ret = OdbcReturn.NoData;
if (ret == OdbcReturn.Success || ret ==
OdbcReturn.SuccessWithInfo)
{
if (outsize >= bufsize || outsize ==
(int)OdbcLengthIndicator.NoTotal) // NoTotal = -4
outsize = bufsize - 1;
int charCount =
defaultDecoder.GetChars(buffer, 0, (int) outsize, charBuffer, 0);
sb1.Append(charBuffer, 0, charCount);
break;
/////////////////////////////////////////////////////// FIXME: Infinite
loop here ?
}
} while (ret != OdbcReturn.NoData);
DataValue = sb1.ToString ();
break;
(I added the break with the FIXME comment.)
For risksand side effects, read thepackage leaflet, or ask
yourdoctororpharmacist.
After this fixes, it's now possible to get the list of CompanyName and
City from the Customers-table in Access !!!
Keep up the good work !
However, there is an additional bug:
For each character with an accent, for example French éèà, etc. and
German Umlauts (äöüÄÖÜ), it displays one character too few at the end of
the word...
I guess this is a bug in the decoder, but it's juuuuust a guess.
Again, isql works correct here, so it really is a mono bug, and not an
mdbtools-deficiency.
But congratulations so far, it's now possible to access and modify an
Access database with mono on Linux.
(using the mdbtools ODBC driver).
/etc/odbc.ini:
[Access_NorthWind_Traders]
Description = Microsoft Access Database
Database = /root/DBs/Nwind.mdb
Driver = /usr/lib/libmdbodbc.so
Setup =
FileUsage = 1
CPTimeout =
CPReuse =
Additionally, SQLConnect in libodbc.cs
has this attribute:
[DllImport ("odbc32.dll", CharSet = CharSet.Unicode)]
However, if Unicode is specified, it doesn't work with a Firebird 2.5 DSN.
All others work fine, however, isql command-line works with all of them,
including Firebird.
It also works fine with Firebird on mono if I specify CharSet.Ansi
There are some further bugs afterwards, however.
(SELECT * FROM employee, in the firebird 2.5 employee example-database)
complete with wrong column names (missing underscore in one column), and
no data if I access that or other rows...
Something is really wrong here. But since FireBird has a managed
provider for mono, it's largely irrelevant.
If I were you, I would really look that Odbc works.
If it does, you could replace SqlClient, OracleClient, etc, with just a
wrapper around Odbc.
That way you needn't fix all those classes whenever a new version
appears (SQL Server, Oracle, Sybase, etc.).
Plus you don't depend on the manufacturers providing an implementation
for mono (Oracle ODP.NET doesn't provide it).
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ximian.com/pipermail/mono-devel-list/attachments/20120117/598adf48/attachment-0001.html>
More information about the Mono-devel-list
mailing list