Description
Submitted by: zxMarce (zxmarce)
I'm enhancing an existing ODBC component for use in Gambas 3, a Visual Basic 6 lookalike for Linux platforms. It works against unixODBC and whatever ODBC driver is set up in the system.
When used with FreeTDS v0.91 against a MSSQL database, SQLGetConnectAttr() with the SQL_ATTR_CURRENT_CATALOG attribute correctly fetches the current catalog name (database name).
Please note that I never call SQLSetConnectAttr() in order to later obtain this value, and I'm using SQLDriverConnect() with a connection string to connect to MSSQL, not a DSN.
When I do the same against a Firebird 2.5 server running on Localhost with a test database, the call returns a two-character string, usually -but not always- a lowercase "L" followed by a non-printable char. The routine is calling SQLGetConnectAttr() twice: First to get the necessary buffer length, second to retrieve the string itself.
After I posted these details to the Firebird-odbc-devel mailing list, I was asked to register an issue here.
In the list I was told that I should first call SQLSetConnectAttr() with SQL_ATTR_CURRENT_CATALOG to get data back, to which I replied that FreeTDS does not need it.
Then I was told that SQLGetConnectAttr() with SQL_ATTR_CURRENT_CATALOG should return SQL_NO_DATA, but it does not; my code checks for ODBC errors after each API call.
My code, called no matter which driver is used, is this (pardon my messy C, I'm not that fluent):
void GetConnectedDBName(DB_DESC *desc, SQLHANDLE *connHandle)
{
SQLRETURN retcode;
SQLINTEGER charsNeeded = 0;
char \*dbName;
if \(DB\.IsDebug\(\)\)
\{
if \(desc\-\>name\)
\{
fprintf\(stderr, "gb\.db\.odbc\.GetConnectedDBName: pre desc\-\>name:'%s'\.\\n", desc\-\>name\);
\} else \{
fprintf\(stderr, "gb\.db\.odbc\.GetConnectedDBName: pre desc\-\>name: NULL\.\\n"\);
\}
\}
if \(desc\-\>name\)
\{
GB\.FreeString\(POINTER\(&desc\-\>name\)\);
\}
//zxMarce: Attribute to fetch is SQL\_ATTR\_CURRENT\_CATALOG
retcode = SQLGetConnectAttr\(connHandle, SQL\_ATTR\_CURRENT\_CATALOG, NULL, \(SQLINTEGER\) 0, \(SQLINTEGER \*\) &charsNeeded\);
if \(SQL\_SUCCEEDED\(retcode\)\)
\{
dbName = malloc\(charsNeeded\+\+\);
dbName\[charsNeeded\+\+\] = 0;
retcode = SQLGetConnectAttr\(connHandle, SQL\_ATTR\_CURRENT\_CATALOG, dbName, charsNeeded, &charsNeeded\);
if \(SQL\_SUCCEEDED\(retcode\)\)
\{
desc\-\>name = GB\.NewZeroString\(dbName\);
\} else \{
reportODBCError\("SQLGetConnectAttr SQL\_ATTR\_CURRENT\_CATALOG \(string\)", connHandle, SQL\_HANDLE\_DBC\);
\}
\} else \{
reportODBCError\("SQLGetConnectAttr SQL\_ATTR\_CURRENT\_CATALOG \(len\)", connHandle, SQL\_HANDLE\_DBC\);
\}
if \(DB\.IsDebug\(\)\)
\{
if \(desc\-\>name\)
\{
fprintf\(stderr, "gb\.db\.odbc\.GetConnectedDBName: post dbName: '%s' desc\-\>name \(%d chars\):'%s'\.\\n", dbName, \(int\)charsNeeded, desc\-\>name\);
\} else \{
fprintf\(stderr, "gb\.db\.odbc\.GetConnectedDBName: post desc\-\>name: NULL\.\\n"\);
\}
\}
if \(dbName\)
\{
free\(dbName\);
\}
}
The routine reportODBCError() is never called. DB.IsDebug() is a flag to post or not low-level debugging info. GB.FreeString and GB.NewZeroString are Gambas 3 API calls to destroy and create Gambas strings.
zxMarce.