OBDC驱动程序字符串转换取决于控制面板/区域设置

时间:2016-01-15 16:22:55

标签: c++ sql-server windows winapi locale

我有一个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驱动程序选项,它完全禁用客户端 字符串翻译?

其他细节:

  • 操作系统:Windows 7 SP1
  • &#34; SQL Server&#34;司机:6.01.7601.17514

1 个答案:

答案 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