我有一个C ++程序,它使用" SQL服务器"驱动程序连接到MSSQL数据库。
它向/从服务器上的varchar
字段插入/读取UTF-8编码的字符串。此操作完全正常
在特定区域设置的情况下。否则,ODBC驱动程序将剥离UTF-8延续字节。
我想实现一个解决方案,它不依赖于Windows操作系统的区域设置。
插入的作品如下:
const char chineseStr[] = "\xE5\x8A\xA0\xE6\xB2\xB9\xE7\xAB\x99";
... // some logic
... // pass chineseStr gdal111.dll (Geospatial Data Abstraction Library)
... // it generates "INSERT INTO ..." query string and after that executes it:
SQLExecDirect(...) // at this point \xE5 is preserved, it was not stripped to \x61
此后调用" SQL服务器"驱动程序将数据发送到服务器。最初出现了错误的结果
数据库:\x61\x8A\xA0\x61\x32\x31\xE7\xAB\x99
。但我知道完全相同的程序运作良好
在其他客户端环境中。在调试了正在运行的进程的注册表访问之后,我猜对了
加载的代码页有问题,因此我在控制面板中更改了此设置:
非Unicode程序的区域和语言/管理/语言。它是" 英语(美国)"
我已将其更改为" 匈牙利语(匈牙利)"并按要求重新启动计算机。鉴于此,
一切运作良好,所以我的程序可以正确读写UTF-8字段和数据库
表示也是正确的。
其他可能的解决方案无效。我试图添加" AutoTranslate=no "到连接字符串, 并调试如下:
SQLAllocConnect(...); // we are in gdal111.dll
...
SQLDriverConnect(...) // parameters after return:
//InConnectionString: DRIVER=SQL Server;Server=MyServerName;Database=MY_DATABASE;UID=username;PWD=passw;AutoTranslate=no;
//OutConnectionString: DRIVER=SQL Server;SERVER=MyServerName;UID=username;PWD=passw;WSID=win_username;DATABASE=MY_DATABASE;AutoTranslate=no
基于OutConnectionString
我假设给定的连接选项到达了驱动程序,但它没有效果。
与语言环境相关的标准函数(例如:std::setlocale
)没有任何效果。之后我尝试了
GetLocaleInfo使用此代码调用:
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTLANGUAGE, (LPTSTR)&buf, bufsize); std::wcout << buf << ",";
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCOUNTRY, (LPTSTR)&buf, bufsize); std::wcout << buf << ",";
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE, (LPTSTR)&buf, bufsize); std::wcout << buf << ",";
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE, (LPTSTR)&buf, bufsize); std::wcout << buf << ",";
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTMACCODEPAGE, (LPTSTR)&buf, bufsize); std::wcout << buf << std::endl;
GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTLANGUAGE, (LPTSTR)&buf, bufsize); std::wcout << buf << ",";
GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTCOUNTRY, (LPTSTR)&buf, bufsize); std::wcout << buf << ",";
GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTCODEPAGE, (LPTSTR)&buf, bufsize); std::wcout << buf << ",";
GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE, (LPTSTR)&buf, bufsize); std::wcout << buf << ",";
GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTMACCODEPAGE, (LPTSTR)&buf, bufsize); std::wcout << buf << std::endl;
我为上述&#34; 非Unicode程序的语言设置了不同的语言后运行了它:&#34;
English (United States) // doesn't work
040e,36,852,1250,10029
0409,1,437,1252,10000
Hungarian (Hungary) // <-- insert/read WORKS (latin2)
040e,36,852,1250,10029
040e,36,852,1250,10029
German (Germany) // doesn't work
040e,36,852,1250,10029
0407,49,850,1252,10000
Greek (Greece) // doesn't work
040e,36,852,1250,10029
0408,30,737,1253,10006
Turkish (Turkey) // doesn't work
040e,36,852,1250,10029
041f,90,857,1254,10081
German (Germany) // +all regional setting set to German in Control Panel --> doesn't work
0407,49,850,1252,10000
0407,49,850,1252,10000
Croatian (Croatia) // <-- insert/read WORKS (latin2)
040e,36,852,1250,10029
041a,385,852,1250,10082
此输出表示codepage 852或1250禁用客户端上的字符串转换。我没有
理解为什么其他人不会像这样工作,以及什么样的代码页差异可能导致字符串
翻译。 &#34; 英语(美国)&#34;在服务器上设置,但我认为它不相关。
也许SetLocaleInfo可以解决问题,但在我发布时它会返回ERROR_INVALID_FLAGS
试图设置系统区域设置。我没有为此找到示例代码,无论如何都不允许。
我如何实施不依赖于控制面板/区域设置的解决方案,以及 不需要重启?或者是否有一个SQL驱动程序选项,它完全禁用客户端 字符串翻译?
答案 0 :(得分:0)
您必须使用各种ODBC API函数的unicode版本。
KB294169: DOC: Explanation of Length Arguments for Unicode ODBC Functions尝试记录Unicode在ODBC API中如何工作的行为
ODBC驱动程序管理器3.5或更高版本支持ANSI和Unicode版本的所有函数,这些函数在其参数中接受指向字符串或SQLPOINTER的指针。 Unicode函数实现为后缀为&#34; W&#34;的函数,例如 SQLExecDirectW 和 SQLGetInfoW 。
例如:
| Ansi | Unicode (Wide) |
|---------------|----------------|
| SQLExecDirect | SQLExecDirectW |
| SQLGetInfo | SQLGetInfoW |
| SQLConnect | SQLConnectW |
您传递每个字符串的UTF-16版本函数,并以字符(而不是字节)传递字符串的长度。
您可以在sqlucode.h
这是ODBC Core函数的unicode包含
如果你定义UNICODE
,它应该自动重新定义SQLExecDirect以使用SQLExecDirectW:
//---------------------------------------------
// Mapping macros for Unicode
//---------------------------------------------
#ifndef SQL_NOUNICODEMAP // define this to disable the mapping
#ifdef UNICODE
#define SQLExecDirect SQLExecDirectW