PHP&;Informix:CLIENT_LOCALE和DB_LOCALE未按预期工作——与编码相关


PHP & Informix: CLIENT_LOCALE and DB_LOCALE not working as expected — encoding related

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

问题是驱动程序正在截断返回字符串的一些值。这很特别字符数加倍。如果列"name"的类型为varchar(2),并且name的值为"áa",则值查询时返回的是"á"而不是"áa"。如果将列的大小调整为varchar(3)结果是正确的。下面我附上一个简短的脚本来重现这个bug。我包含了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'

有什么想法吗?

有点奇怪的是,我认为这是"预期的"或"按设计工作"行为。

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

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

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

这是一个有趣的设置,客户端和数据库服务器使用不同的代码集。当进行代码集转换时,客户端可以有效地使用更大的变量大小。由于数据库存储Latin-1,所有字符都属于Unicode范围U+0000.U+00FF。修复程序可能属于PDO Informix。它使用CSDK和Informix服务器提供的字节计数信息,告诉CSDK要使用多少空间来存储数据。


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