2016-02-23 52 views
0

我有一個構建在RHEL 5上的C++應用程序,它通過位於Windows機器上的freeTDS和unixODBC連接到MS SQL 2008。無法在MS SQL 2008中通過freetds unixODBC插入unicode字符

這是應用程序發送到數據庫的查詢。

INSERT INTO mytable (SAMPLE) VALUES(N'乕乭乺丕')

[email protected]@Iz被調用上述查詢時被實際插入到數據庫中。

以下是我使用的配置 -

== freetds.conf == 
[myserver.mydomain.com] 
client charset = UTF-16 
debug flags = 0xffff 
dump file = /tmp/dump.log 
dump file append = yes 
host = 127.0.01 
port = 1433 
tds version = 7.3 

== odbcinst.ini == 
[FreeTDS Driver] 
Description  = FreeTDS 
Driver   = /usr/lib64/libtdsodbc.so.0 

== odbc.ini == 
[mydsn] 
Description  = MS SQL connection to 'mydb' database 
Driver   = FreeTDS Driver 
Servername  = myserver.mydomain.com 
Port   = 1433 
TDS_Version  = 7.3 
Database  = mydb 
UserName  = sa 
Password  = mypassword 
Trace   = Yes 
TraceFile  = /tmp/odbc.log 
ForceTrace  = Yes 

我可以直接通過

INSERT INTO mytable (SAMPLE) VALUES(N'乕乭乺丕')但不是通過freetds的和unixODBC的數據插入到數據庫

請查找代碼我使用如下:

#include <iostream> 

#ifdef WIN32 
    #include <windows.h> 
#endif 

#include <sql.h> 
#include <sqlext.h> 
#include <sqltypes.h> 

#include "unicode/ustdio.h" 

using namespace std; 

int main (int argc, char* argv[]) 
{ 
    SQLHSTMT hSQLStatement = 0; 
    SQLHENV hSQLEnvironment = 0; 
    SQLHDBC hSQLODBC = 0; 

    SQLRETURN sqlRet = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hSQLEnvironment); 

    if(SQL_SUCCEEDED(sqlRet)) 
    { 
    sqlRet = SQLSetEnvAttr(hSQLEnvironment, 
          SQL_ATTR_ODBC_VERSION, 
          (void*)SQL_OV_ODBC3, 
          0); 

    if(SQL_SUCCEEDED(sqlRet)) 
    { 
     sqlRet = SQLAllocHandle(SQL_HANDLE_DBC, 
           hSQLEnvironment, 
           &hSQLODBC); 
    } 
    else 
    { 
     cout << "Error in SQLAllocHandle for SQL_HANDLE_DBC" << endl; 
    } 
    } 
    else 
    { 
    cout << "Error in SQLAllocHandle for SQL_HANDLE_ENV" << endl; 
    } 

    UnicodeString DSNName = "mydsn"; 
    UnicodeString UserName = "sa"; 
    UnicodeString Password = "mypassword"; 

    UnicodeString Value = ""; 

    UChar32 character = 20053; 
    Value.append(character); 

    character = 20077; 
    Value.append(character); 

    character = 131140; 
    Value.append(character); 

    character = 131145; 
    Value.append(character); 

    character = 20090; 
    Value.append(character); 

    character = 19989; 
    Value.append(character); 

    UnicodeString SQLStatement = "INSERT INTO mytable (sample) VALUES(N"; 
    SQLStatement.append("'"); 
    SQLStatement.append(Value); 
    SQLStatement.append("'"); 
    SQLStatement.append(")"); 

    if(0 != hSQLODBC) 
    { 
    SQLRETURN sqlRet = SQLConnectW(hSQLODBC, 
            (SQLWCHAR*)DSNName.getTerminatedBuffer(), 
            SQL_NTS, 
            (SQLWCHAR*)UserName.getTerminatedBuffer(), 
            SQL_NTS, 
            (SQLWCHAR*)Password.getTerminatedBuffer(), 
            SQL_NTS); 

    if(SQL_SUCCEEDED(sqlRet)) 
    { 
     cout << "Connection to database successful" << endl; 

     SQLRETURN sqlRet = SQLAllocHandle(SQL_HANDLE_STMT, 
             hSQLODBC, 
             &hSQLStatement); 

     if(SQL_SUCCEEDED(sqlRet)) 
     { 
     sqlRet = SQLExecDirectW(hSQLStatement, 
           (SQLWCHAR*)SQLStatement.getTerminatedBuffer(), 
           SQL_NTS); 

     if(SQL_SUCCEEDED(sqlRet)) 
     { 
      cout << "Query Execution successful" << endl; 
     } 
     else 
      cout << "Query Execution failed" << endl; 
     } 
    } 
    else 
    { 
     cout << "Connection to database failed" << endl; 
    } 
    } 

    return 0; 
} 

有什麼想法可能是錯誤的?

編輯1:添加示例代碼

編輯2:更新按照奧利弗的建議

+1

「SAMPLE」列的數據類型必須爲「NVARCHAR」 –

+0

是數據類型爲「NVARCHAR」 – D3XT3R

+0

您使用的是哪種FreeTDS版本? 0.95,0.91? TDS版本7.3僅在FreeTDS 0.95中受支持。我相信0.91附帶RHEL 6,但我不確定RHEL 5. – FlipperPA

回答

0

SQL Server使用UTF-16 NVARCHAR。從你問題中的信息看來,你有UTF-8中的字符串。首先將插入語句轉換爲UTF-16,然後再將它發送到SQL Server。


更新:我看到你添加了代碼示例。我看到您將UChar32值附加到UnicodeString實例。這些是4個字節寬。 AFAICT您需要appendUChar值(2個字節寬)。

+0

當通過使用SQL Server Native Client 10.0' odbc驅動程序在windows上構建的C++應用程序調用時,成功插入數據庫。我不確定FreeTDS在這裏可能會做什麼。 – D3XT3R

+0

@ D3XT3R看一下實際插入的內容,這個縮小到單個字節的味道,而不是UTF-16字符串中的雙字節。就像一個測試將字符串轉換爲字節數組,並插入字符串'INSERT INTO mytable(sample)VALUES(CAST(0x AS NVARCHAR(4000))',其中字節模式是HEX中的一系列字節表單爲** UTF-16 ** –

+0

@ D3XT3R你應該真的考慮在你的問題中添加一個[MVCE](https://stackoverflow.com/help/mcve),也就是你重現問題的代碼有可能問題出在你的代碼中,而不是FreeDTS驅動程序中。你使用的字符串類型是UTF-16嗎? –

0

ICU UnicodeString此處的文檔(https://ssl.icu-project.org/apiref/icu4c/classicu_1_1UnicodeString.html#details)指出:「在ICU中,Unicode字符串由16位Unicode代碼單元組成。」由於您使用SQLStatement.getTerminatedBuffer()來獲取該數據,因此當您抓住它並將其推入SQLExecDirectW()時,我將其讀爲UTF-16中的數據。

另一方面,您可以在FreeTDS配置中指定client charset = UTF-8。由於它與Native Client一起工作,我會嘗試將FreeTDS客戶端的字符集更改爲UTF-16。

+0

更新我的字符集爲UTF-16,同樣的問題依然存在。 – D3XT3R

相關問題