FirebirdSQL / firebird-odbc-driver

Firebird ODBC driver
https://firebirdsql.org/en/odbc-driver/
42 stars 11 forks source link

SQLGetConnectAttr() misbehaves. [ODBC202] #188

Open firebird-automations opened 8 years ago

firebird-automations commented 8 years ago

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.

firebird-automations commented 5 years ago

Commented by: Julien Nabet (julien2412)

So perhaps this patch may help: diff --git a/OdbcConnection.cpp b/OdbcConnection.cpp index cd27689..0afb9d7 100644 --- a/OdbcConnection.cpp +++ b/OdbcConnection.cpp @@ -2060,6 +2060,7 @@ SQLRETURN OdbcConnection::sqlGetConnectAttr(int attribute, SQLPOINTER ptr, int b

    case SQL\_ATTR\_CURRENT\_CATALOG:
            string = databaseName;

+ value = SQL_NO_DATA; break;

    case SQL\_LOGIN\_TIMEOUT:                 //   103
irodushka commented 2 months ago

That's what I see with ODBC v3.0

    Full Connect(Default)

    Env. Attr. SQL_ATTR_ODBC_VERSION set to SQL_OV_ODBC3

    Successfully connected to DSN 'EMPL'.
SQLGetConnectAttr:
                In:             ConnectionHandle = 0x0000000005063030, Attribute = Conn: SQL_ATTR_CURRENT_CATALOG=109, ValuePtr = 0x00000000005172A0, 
                                        BufferLength = 600, StringLengthPtr = 0x000000000050A3C0, fAttribute Type = SQL_C_WCHAR=-8
                Return: SQL_SUCCESS=0
                Out:            *ValuePtr = "C:\Program Files\Firebird\Firebird_4_0\examples\empbui...", *StringLengthPtr = 138

Seems to be ok. Please try to reproduce it again, and if the problem persists, describe your case in details pls. Regards.