1

我使用的是 PHP PDO_Informix 驱动程序 v1.2.7,Informix 客户端版本是 3.70。我有一些 UTF-8 代码可以查询 Latin1 数据库(Informix 服务器是 9.21)。

问题是驱动程序正在砍掉返回字符串的一些值。这就像特殊字符计数加倍。如果列 'name' 的类型为 varchar(2) 并且 name 的值为 'áa',则查询时返回的值是 'á' 而不是 'áa'。如果我将列大小调整为 varchar(3) 结果是正确的。下面我附上一个简短的脚本来重现这个错误。我包含了 DSN,因此您可以查看编码设置。

测试脚本:

$dsn = "informix:database=base;server=ol_server;host=192.168.123.123;client_locale=en_us.utf8;db_locale=en_us.819;service=1526;protocol=olsoctcp;EnableScrollableCursors=1";
$db = new \PDO($dsn, 'user', 'pass');
$db->exec("CREATE TABLE ticket82 ( name VARCHAR(2) );");
$db->exec("INSERT INTO ticket82 VALUES ('aa');");

$statement = $db->query("select name from ticket82;");
$value = $statement->fetchAll(\PDO::FETCH_ASSOC);
echo "expected 'aa' got '{$value[0]['NAME']}'\n";

$db->exec("update ticket82 set name='áa';");
$statement = $db->query("select name from ticket82;");
$value = $statement->fetchAll(\PDO::FETCH_ASSOC);
echo "expected 'áa' got '{$value[0]['NAME']}'\n";

$db->exec("ALTER TABLE ticket82 MODIFY (name varchar(3));");
$statement = $db->query("select name from ticket82;");
$value = $statement->fetchAll(\PDO::FETCH_ASSOC);
echo "expected 'áa' got '{$value[0]['NAME']}'\n";

$db->exec("DROP TABLE ticket82;");

预期结果:

expected 'aa' got 'aa'
expected 'áa' got 'áa'
expected 'áa' got 'áa'

实际结果:

expected 'aa' got 'aa'
expected 'áa' got 'á'
expected 'áa' got 'áa'

有任何想法吗?

4

1 回答 1

1

以一种有点奇怪的方式,我认为这是“预期”或“按设计工作”的行为。

列大小以字节而不是字符为单位指定,但对于数据库代码集(ISO 8859-1 aka Latin-1)没有区别。客户端代码 (PDO Informix) 假定保存它的变量应该允许相同数量的字节存储。

但是,客户端代码集是 UTF-8 而不是 8859-1,并且 8859-1 字符的某些字符代码在 UTF-8 中需要 2 个字节。准确地说,“ASCII”范围 U+0000..U+007F 在 UTF-8 中需要 1 个字节,但“重音”范围 U+0080..U+00FF 需要 2 个字节。由于客户端已将其变量限制为 2 个字节(而不是 2 个字符),因此您将只能从 VARCHAR(2) 列中选择一个重音字符。

UTF-8 和 8859-1 之间的代码集转换发生在 PDO Informix 使用的 Informix ClientSDK (CSDK) 代码中称为 GLS(全球语言支持)的库中。

这是一个有趣的设置,客户端和数据库服务器使用不同的代码集。当进行代码集转换时,可以认为客户端可以有用地使用更大的变量大小。由于数据库存储的是 Latin-1,所有字符都在 Unicode 范围内 U+0000..U+00FF。(例如,如果是 Latin-15,欧元符号 € U+20AC 在 UTF-8 中需要 3 个字节;我相信,大多数其他 8859-x 系列代码集每个字符需要一个或两个字节。)在代码集转换环境中明智地需要一些小心,但如果代码知道该问题,则可以这样做。该修复程序可能属于 PDO Informix。它使用 CSDK 和 Informix 服务器提供的字节数信息告诉 CSDK 使用多少空间来存储数据。


仅供参考:Informix 9.21 已经失去支持很长时间了(9.30、9.40 和 10.00 也是如此——甚至 11.10 也失去了支持,尽管这是一个相对较新的变化)。然而,这不是这个问题的一个因素。

于 2012-08-22T14:40:47.877 回答