2016-02-23 4 views
0

У меня есть приложение C++, построенное на RHEL 5, которое подключается к MS SQL 2008 через freeTDS и unixODBC, расположенные на машине Windows.Невозможно вставить символы Юникода через freetds unixODBC в MS SQL 2008

Это запрос, который приложение отправляет в базу данных.

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; 
} 

Подумайте, что здесь может быть неправильным?

EDIT 1: Добавлен пример кода

EDIT 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. Сначала преобразуйте оператор insert в UTF-16 перед отправкой его на SQL Server.


Обновление: Я вижу, что вы добавили образец кода. Я вижу, что вы добавляете значения UChar32 в экземпляр UnicodeString. Они имеют ширину 4 байта. AFAICT вам необходимо appendUChar значения (2 байта в ширину).

+0

Тот же запрос при вызове с помощью приложения C++, построенного на окнах с использованием драйвера SQL Server Native Client 10.0' odbc успешно вставлен в базу данных. Я не уверен, что здесь может делать 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(), чтобы получить эти данные, я прочитал это как данные, находящиеся в UTF-16, когда вы его захватите и вставьте в SQLExecDirectW().

С другой стороны, вы указываете client charset = UTF-8 в своей конфигурации FreeTDS. Поскольку он работает с собственным клиентом, я попытаюсь изменить кодировку для клиента FreeTDS на UTF-16.

+0

обновил мою кодировку до UTF-16, эта же проблема сохраняется. – D3XT3R