none
Multiple SQL_HANDLE_DBC handles do not work on Linux

    Question

  • Hello,

    I am seeing the following error from the SQL Server Driver For Linux when I attempt to execute a query on a SECOND connection within my application:

    SQLSTATE: IM001
    Native Error Code: 0
    Message: [unixODBC][Driver Manager]Driver does not support this function

    I have compiled/run the test case I have on Windows and the code executes without issue.

    Here is my test case:

    // SQLGetData.cpp
    //
    // g++ -M64 -I$ODBC/include -L$ODBC/lib -g -lodbc sqlgetdata.cpp
    // cl sqlgetdata2.cpp odbc32.lib
    //
    // CREATE TABLE tstDFRBLB(col1 varbinary(max))
    
    #if defined(_WIN32)
    #include <windows.h>
    #endif
    
    #include <stdlib.h>
    #include <stdio.h>
    
    #include <sql.h>
    #include <sqlext.h>
    
    void checkError ( SQLRETURN rc, const char *cstr )
    {
        if( rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO ) {
            return ;
        } else if( rc == SQL_INVALID_HANDLE ) {
            fprintf( stderr, "Error: invalid handle: %s.\n", cstr ) ;
        } else {
            fprintf( stderr, "Unknown Error occured in %s: code %d.\n", cstr, rc ) ;
        }
    }
    
    void checkStmtError( SQLRETURN rc, SQLHSTMT stmth )
    { 
        if(rc != SQL_SUCCESS) {
            int i = 1 ;
            SQLSMALLINT length;
            
            SQLINTEGER sqlcode;
            SQLCHAR *sqlstate = (SQLCHAR *) malloc(100  * sizeof(SQLCHAR));
            SQLCHAR *message  = (SQLCHAR *) malloc(1000 * sizeof(SQLCHAR));
            
            while ( SQLGetDiagRec( SQL_HANDLE_STMT, stmth, i, sqlstate, &sqlcode, 
                       message, 1000, &length ) == SQL_SUCCESS ) {
               printf( "\nSQLSTATE: %s\n", sqlstate ) ;
               printf( "Native Error Code: %ld\n", sqlcode ) ;
               printf( "Message: %s\n", message ) ;
               i++ ;
            }
           
           delete sqlstate;
           delete message;
        }
    }
    
    int main( int ac, char **av )
    {
        SQLHENV    envh ;
        SQLHDBC    dbch ;
        SQLHDBC    dbch2 ;
    
        SQLRETURN    rc ;
        SQLHSTMT    stmth ;
    
        const char    *select_stmt = "SELECT * FROM tstDFRBLB" ;
        
        /* Allocate a environment handl */
        rc = SQLAllocHandle( SQL_HANDLE_ENV,    // Handle type
                 SQL_NULL_HANDLE,    
                 &envh            // SQLHENV handle (environment)
                   ) ; 
        checkError( rc, "SQLAllocHandle - SQL_HANDLE_ENV" ) ;
    
    
        /* Set environment attributes */
        rc = SQLSetEnvAttr( envh,         // Environment handle
                SQL_ATTR_ODBC_VERSION,    // Attribute to set
                (SQLPOINTER) SQL_OV_ODBC3,// New attribute
                SQL_NTS                   // SQL_NTS (null terminated)
             ) ;
        checkError( rc, "SQLSetEnvAttr" ) ;
    
        /* Allocate a database connection handle */
        rc = SQLAllocHandle( SQL_HANDLE_DBC,    // Handle Type
                 envh,            // Where to attatch the new handle
                 &dbch            // Pointer to new handle
                   ) ;
        checkError( rc, "SQLAllocHandle - SQL_HANDLE_DBC" ) ;
    
        /* Establish a connection */
        SQLCHAR outStr[1024];
        SQLSMALLINT outSize;
        rc = SQLDriverConnect(dbch, NULL,
    #if defined(_WIN32)
                          (SQLCHAR*)"DSN=MSSQL_2012_NC_64;UID=*****;PWD=*****;DATABASE=qe1;", 57,
    #else
                          (SQLCHAR*)"DSN=mssql-2012-md_64;UID=*****;PWD=*****;DATABASE=qe1;", 57,
    #endif
                          outStr, sizeof(outStr), &outSize, SQL_DRIVER_NOPROMPT);    
       /* Allocate a second database connection handle */
        rc = SQLAllocHandle( SQL_HANDLE_DBC,    // Handle Type
                 envh,            // Where to attatch the new handle
                 &dbch2            // Pointer to new handle
                   ) ;
        checkError( rc, "SQLAllocHandle - SQL_HANDLE_DBC" ) ;
    
        rc = SQLSetConnectAttr(dbch2,
                SQL_ODBC_CURSORS,
                (SQLPOINTER)SQL_CUR_USE_DRIVER,
                (SQLINTEGER)NULL); // this value is ignored
        checkError( rc, "SQLSetConnectAttr - SQL_ODBC_CURSORS" ) ;
    
        rc = SQLDriverConnect(dbch2, NULL,
    #if defined(_WIN32)
                          (SQLCHAR*)"DSN=MSSQL_2012_NC_64;UID=*****;PWD=*****;DATABASE=qe1;", 57,
    #else
                          (SQLCHAR*)"DSN=mssql-2012-md_64;UID=*****;PWD=*****;DATABASE=qe1;", 57,
    #endif
                          outStr, sizeof(outStr), &outSize, SQL_DRIVER_NOPROMPT);    
        rc = SQLAllocHandle( SQL_HANDLE_STMT, dbch2, &stmth ) ;
        checkError( rc, "SQLAllocHandle - SQL_HANDLE_STMT" ) ;
    
        /*
        ** Read the value back
        */
        rc = SQLExecDirect( stmth, (SQLCHAR*)select_stmt, SQL_NTS ) ;
        checkStmtError( rc, stmth );
    
        char outWData[168000];
        SQLLEN  outInd = 0;
        while ( SQLFetch( stmth ) == SQL_SUCCESS )
        {
            rc = SQLGetData( stmth, 1, SQL_C_BINARY, outWData, sizeof(outWData), &outInd );
            checkStmtError( rc, stmth );
            
            if(outInd == SQL_NULL_DATA) {
                printf("Data Returned: NULL\n");
            }
            else {
                printf("Data Returned Length %d\n", outInd);
            }
    
            rc = SQLMoreResults(stmth);
            checkStmtError( rc, stmth );
        }
    
    
        /* Disconnect from the database */
        rc = SQLDisconnect( dbch2 ) ;
        checkError( rc, "SQLDisconnect" ) ;
    
        /* Free connection and environment handles */
        rc = SQLFreeHandle( SQL_HANDLE_DBC, dbch2 ) ;
        checkError( rc, "SQLDisconnect" ) ;
    
        /* Disconnect from the database */
        rc = SQLDisconnect( dbch ) ;
        checkError( rc, "SQLDisconnect" ) ;
    
        /* Free connection and environment handles */
        rc = SQLFreeHandle( SQL_HANDLE_DBC, dbch ) ;
        checkError( rc, "SQLDisconnect" ) ;
    
        SQLFreeHandle( SQL_HANDLE_ENV, envh ) ;
        checkError( rc, "SQLDisconnect" ) ;
    
        return EXIT_SUCCESS ;
    }
    

    Thank you for any help/advice.

    Dave


    David Ritter

    Wednesday, March 27, 2013 8:36 PM

All replies

  • Hi David,

    According to your description, the code running smoothly in windows, and getting this problem when using SQL Server driver for linux.

    So, what's the version of your SQL Server driver for linux?

    As per the error message, the function is not supported, so could you please check the configuration of the driver or there are some limitation in the driver you used?

    Please follow these links to have a check:

    The ODBC Driver 11 for SQL Server on 64-bit Red Hat Enterprise Linux 5 and 64-bit Red Hat Enterprise Linux 6.

    You can download the ODBC driver for Red Hat at Microsoft ODBC Driver for SQL Server.


    Iric Wen
    TechNet Community Support


    Thursday, March 28, 2013 7:04 AM
  • Hello Iric,

    I'm fairly certain there is some other issue going on that the Function not being supported.  As I noted, this error occurs when I used that SECOND connection created in my test case. If I update the code to allocate the statement handle from the first connection (instead of the second one), the SQLGetData call executes successfully.

    I am using the ODBC 10.0 Driver for Linux.  We are unable to upgrade to the ODBC 11 Driver.  That said I have downloaded the ODBC 11 driver and tried it out in a Virtual Machine and I see the same behavior as I do with the 10.0 Driver.

    Dave


    David Ritter

    Thursday, March 28, 2013 1:47 PM