无法在MS SQL 2008中通过freetds unixODBC插入unicode字符
我有一个构建在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:更新按照奥利弗的建议
SQL Server使用UTF-16 NVARCHAR
。从你问题中的信息看来,你有UTF-8中的字符串。首先将插入语句转换为UTF-16,然后再将它发送到SQL Server。
更新:我看到你添加了代码示例。我看到您将UChar32
值附加到UnicodeString
实例。这些是4个字节宽。 AFAICT您需要append
UChar
值(2个字节宽)。
当通过使用SQL Server Native Client 10.0' odbc驱动程序在windows上构建的C++应用程序调用时,成功插入数据库。我不确定FreeTDS在这里可能会做什么。 – D3XT3R
@ D3XT3R看一下实际插入的内容,这个缩小到单个字节的味道,而不是UTF-16字符串中的双字节。就像一个测试将字符串转换为字节数组,并插入字符串'INSERT INTO mytable(sample)VALUES(CAST(0x
@ D3XT3R你应该真的考虑在你的问题中添加一个[MVCE](https://stackoverflow.com/help/mcve),也就是你重现问题的代码有可能问题出在你的代码中,而不是FreeDTS驱动程序中。你使用的字符串类型是UTF-16吗? –
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。
更新我的字符集为UTF-16,同样的问题依然存在。 – D3XT3R
“SAMPLE”列的数据类型必须为“NVARCHAR” –
是数据类型为“NVARCHAR” – D3XT3R
您使用的是哪种FreeTDS版本? 0.95,0.91? TDS版本7.3仅在FreeTDS 0.95中受支持。我相信0.91附带RHEL 6,但我不确定RHEL 5. – FlipperPA