【问题标题】:Character set mismatch on Linux with ODBC to SQL Server使用 ODBC 到 SQL Server 的 Linux 上的字符集不匹配
【发布时间】:2016-05-10 14:23:48
【问题描述】:

我遇到了一个有趣的问题,尝试使用适用于 Linux 的 Microsoft ODBC 驱动程序将非 ASCII 字符插入 SQL Server 数据库。问题是它似乎在发送和接收数据时假设了不同的字符集。有关信息,服务器排序规则设置为 Latin1_General_CI_AS(我只是尝试插入欧洲重音字符)。

使用 tsql(FreeTDS 附带)进行测试,一切正常。在启动时,它会输出以下内容:

locale is "en_GB.utf8"
locale charset is "UTF-8"
using default charset "UTF-8"

我可以在表格中插入和选择一个非 ASCII 值。

但是,使用我自己的使用 ODBC API 的实用程序,它不起作用。当我进行选择查询时,数据会根据需要以 UTF-8 字符集返回。但是,如果我插入 UTF-8 字符,它们就会损坏。

SQL > update test set a = 'Béthune';
Running SQL: update test set a = 'Béthune'
Query executed OK: 1 affected rows
SQL > select * from test;
Running SQL: select * from test
+------------+
| a          |
+------------+
| Béthune |
+------------+

如果我改为插入以 ISO-8859-1 编码的数据,则可以正常工作,但是选择查询仍将返回以 UTF-8 编码的数据!

我已经将语言环境设置为en_GB.utf8,并在数据库连接详细信息中设置了UTF-8 的client charset。啊!

FWIW 无论我使用 FreeTDS 驱动程序还是微软官方驱动程序,我似乎都遇到了同样的问题。

编辑:刚刚意识到一个相关点,那就是在这个测试程序中,它没有使用带有绑定变量的准备好的语句。换句话说,更新 SQL 直接传递到 SQLPrepare 调用中。 ODBC 中的某些东西肯定是在进行 iconv 翻译,但显然不是正确的字符集!

#0  0x0000003d4c41f850 in iconv () from /lib64/libc.so.6
#1  0x0000003d4d83fd94 in ?? () from /usr/lib64/libodbc.so.2
#2  0x0000003d4d820465 in SQLPrepare () from /usr/lib64/libodbc.so.2

我将尝试编译我自己的 UnixODBC,以更好地了解发生了什么。

编辑 2:我已经从源代码构建了 UnixODBC 来调试它在做什么,问题是 nl_langinfo(CODESET) 报告回 ISO-8859-1。这很奇怪,因为它的手册页说它与您从locale charmap 获得的字符串相同,它返回UTF-8。我猜这就是问题所在,但仍然不知道如何解决。

【问题讨论】:

    标签: c sql-server character-encoding odbc freetds


    【解决方案1】:

    工作中的一位同事至少想出了 FreeTDS 的解决方案。

    对于直接驱动程序连接 (SQLDriverConnect()),将 ClientCharset=UTF-8;ServerCharset=CP1252; 添加到连接字符串可解决问题

    对于通过驱动程序管理器 (SQLConnect()) 的连接,我可以将这些行添加到 odbc.ini 中的连接设置中:

    client charset = UTF-8
    server charset = CP1252
    

    目前还无法找到使用 Microsoft 驱动程序的解决方案...

    【讨论】:

    • 感谢您的帖子,我能够在 PHP/Ubuntu/MSSQL/FreeTDS/PDO/ODBC 中使用正确的 DSN 连接字符串,方法是:“odbc:DRIVER=FreeTDS;SERVER=serverhostname\SQLEXPRESS;DATABASE =testdb;ClientCharset=WE8ISO8859P1"
    • 仍然无法让它与适用于 MacOS/Linux 的最新 Microsoft ODBC 驱动程序一起工作。驱动程序管理器的调试输出或错误消息显示为:警告:QODBCResult::exec: 无法执行语句:“[Microsoft][ODBC Driver 13 for SQL Server][SQL Ser\u0000\u0000\u0000\u0000\ u0002\u0000뜠\u0BFF\u0001\u0000\u0000\u0000\u0000㿰\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000㿰\u0000\u0000\u0000\u0000\u0000 \u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000㿰\u0000\u0000[\u0000\u0000"
    【解决方案2】:

    Microsoft ODBC Driver 的解决方案可能是在 LANG 环境变量中设置适当的值。

    确保您已安装和配置所需的语言环境。还要确保为您运行应用程序的用户正确设置了LANG 环境变量。这对于守护进程可能很棘手。例如,为了使其适用于 Apache2 的 PHP,我必须将 export LANG=en_US.utf8 添加到 /etc/apache2/envvars

    【讨论】:

    • 请注意,如果系统没有您需要的带有字符集的语言环境,您可以定义它。使用locale -m 列出字符集。使用它来定义带有字符集的语言环境:localedef -f CP1250 -i pl_PL /usr/lib/locale/pl_PL.cp1250
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-03
    相关资源
    最近更新 更多