ubuntu下使用unixODBC+ODBC Driver 11 for SQL Server 连接SQL Server

上一篇讲了如何安装unixODBC+ODBC Driver 11 for SQL Server,安装完毕以后,我发现其实使用DSN方式根本就不能连接到数据库.在配置了DSN

sudo vim /etc/odbc.ini

[mhdsn]
Driver = /opt/microsoft/msodbcsql/lib64/libmsodbcsql-11.0.so.2270.0
Description = Microsoft ODBC Driver 11 for SQL Server
Trace = Yes
Server = 111.111.111.111
Port = 1433
Database = mhdb
Socket=tcp
 而另一个配置则为 
  

  ~  cat /etc/odbcinst.ini 

[ODBC Driver 11 for SQL Server]
Description=Microsoft ODBC Driver 11 for SQL Server
Driver=/opt/microsoft/msodbcsql/lib64/libmsodbcsql-11.0.so.2270.0
Threading=1
UsageCount=1

[ODBC]
Trace = Yes
TraceFile = /tmp/odbc.log

在这情况下,我使用微软的sqlcmd连接服务器,是失败的,原因不知道,情况如下:

➜  ~  sqlcmd -S mhdsn
Sqlcmd: Error: Microsoft ODBC Driver 11 for SQL Server : Login timeout expired.
Sqlcmd: Error: Microsoft ODBC Driver 11 for SQL Server : A network-related or instance-specific error has occurred while establishing a connection to SQL Server. Server is not found or not accessible. Check if instance name is correct and if SQL Server is configured to allow remote connections. For more information see SQL Server Books Online..
Sqlcmd: Error: Microsoft ODBC Driver 11 for SQL Server : TCP Provider: Error code 0x2AF9.
但是我发现使用sqlcmd指定服务器连接却是成功的

 sqlcmd -U sa -S 111.111.111.111,1433

想到SQL Server有两种认证方式,一种就是windows验证,一种就是账号认证.有可能是sqlcmd -S mhdsn使用了windows验证.而后面我使用用户登录却是可以的.所以我估计用代码跑上一次,应该也是可以成功的.

使用的测试代码,基本上微软的代码,简单修改了一点儿.代码如下:

#include 
#include 
#include 
#include 
#include 

#define NAME_LEN 50
#define PHONE_LEN 20

void show_error()
{
    printf ( "error\n" );
}

int main()
{
    SQLHENV henv;
    SQLHDBC hdbc;
    SQLHSTMT hstmt = 0;
    SQLRETURN retcode;
    SQLCHAR szName[NAME_LEN], szPhone[PHONE_LEN], sCustID[NAME_LEN];
    SQLLEN cbName = 0, cbCustID = 0, cbPhone = 0;

    // Allocate environment handle
    retcode = SQLAllocHandle ( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv );

    // Set the ODBC version environment attribute
    if ( retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO )
    {
        retcode = SQLSetEnvAttr ( henv, SQL_ATTR_ODBC_VERSION, ( SQLPOINTER* ) SQL_OV_ODBC3, 0 );

        // Allocate connection handle
        if ( retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO )
        {
            retcode = SQLAllocHandle ( SQL_HANDLE_DBC, henv, &hdbc );

            // Set login timeout to 5 seconds
            if ( retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO )
            {
                SQLSetConnectAttr ( hdbc, SQL_LOGIN_TIMEOUT, ( SQLPOINTER ) 5, 0 );

                // Connect to data source
                // retcode = SQLConnect ( hdbc, ( SQLCHAR* ) "SQLCMD", SQL_NTS, ( SQLCHAR* ) "Test1", 5, ( SQLCHAR* ) "Password1", 9 );

                SQLCHAR OutConnStr[2048]= {0};
                SQLSMALLINT OutConnStrLen;
                SQLCHAR InConnectionString[] = {"DRIVER={ODBC Driver 11 for SQL Server};"
                "SERVER={111.111.111.111,1433};UID={sa};PWD={xxxxxxxx};"};

                retcode = SQLDriverConnect ( hdbc,NULL, ( SQLCHAR* ) InConnectionString,sizeof ( InConnectionString ),
                                             OutConnStr, sizeof ( OutConnStr ),&OutConnStrLen,SQL_DRIVER_NOPROMPT );

                // Allocate statement handle
                if ( retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO )
                {
                    retcode = SQLAllocHandle ( SQL_HANDLE_STMT, hdbc, &hstmt );

                    retcode = SQLExecDirect ( hstmt, ( SQLCHAR * ) "SELECT CustomerID, ContactName, Phone FROM CUSTOMERS ORDER BY 2, 1, 3", SQL_NTS );
                    if ( retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO )
                    {

                        // Bind columns 1, 2, and 3
                        retcode = SQLBindCol ( hstmt, 1, SQL_C_CHAR, sCustID, 100, &cbCustID );
                        retcode = SQLBindCol ( hstmt, 2, SQL_C_CHAR, szName, NAME_LEN, &cbName );
                        retcode = SQLBindCol ( hstmt, 3, SQL_C_CHAR, szPhone, PHONE_LEN, &cbPhone );

                        // Fetch and print each row of data. On an error, display a message and exit.
                        for ( int i=0 ; ; i++ )
                        {
                            retcode = SQLFetch ( hstmt );
                            if ( retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO )
                                show_error();
                            if ( retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO )
                                printf ( "%d: %s %s %s\n", i + 1, sCustID, szName, szPhone );
                            else
                                break;
                        }
                    }

                    // Process data
                    if ( retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO )
                    {
                        SQLCancel ( hstmt );
                        SQLFreeHandle ( SQL_HANDLE_STMT, hstmt );
                    }

                    SQLDisconnect ( hdbc );
                }
                else
                {
                    printf ( "retcode=%d, DriverConnect Failed.\n", retcode );

                    SQLCHAR sqlstate[255];
                    SQLINTEGER nativeErrorPtr;

                    retcode = SQLGetDiagRec ( SQL_HANDLE_DBC, hdbc, 1, sqlstate, &nativeErrorPtr, OutConnStr, 255, &OutConnStrLen );
                    printf ( "SQLDriverConnect failed with ret=%d, errText=%s.\n", retcode, OutConnStr );

                }

                SQLFreeHandle ( SQL_HANDLE_DBC, hdbc );
            }
        }
        SQLFreeHandle ( SQL_HANDLE_ENV, henv );
    }
}
以上代码在我的机器上可以工作,ubtuntu14.04,我花了点功夫在SQLDriverConnect在连接字符串上,而且我是从上面的trace log中看到的连接方法,就拿过来修改了.因为我在odbcinst.ini上面添加了Trace = Yes TraceFile = /tmp/odbc.log 所在查看/tmp/odbc.log,可以看出来使用sqlcmd失败的时候,具体原因是什么.有时候猛一看挺乱的,不知道错在什么地方,但认真看下去,会发现,我晕,原来它一直都是在调用odbc的API啊,到SQLDriverConnect挂了.看一看SQLDriverConnect它的连接参数,发现原来是这样拼的啊.所以经验挺重要的,没失败过,就要多花一点时间在上面搞了.











你可能感兴趣的:(LINUX,学习,黎宏伟)