锁定老帖子 主题:让MySQL支持欧元字符
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|||
---|---|---|---|
作者 | 正文 | ||
发表时间:2010-11-14
最后修改:2010-11-14
本文说明一下MySQL中不支持欧元字符的原因及解决方法。
1、 问题描述 在mysql中插入的字符串中若包含欧元字符(€),会发现该字符及以后的字符串都变得“不可见”。实际上这里并非不可见,而是根本没有进入数据库中。简单描述步骤如下:
可以看到,我们试图插入三个字符(a, €, b), 但在查询中发现只有一个字符a. Insert的一个warning内容为 Incorrect string value: '\x80b' for column 'c' at row 1 说明在插入0x80(即€) 时出错,导致后面的字符也一起被丢弃.
2、 原因分析 我们知道,在mysql将语句中设置的值传给引擎时,需要先拷贝到一个临时结构中。但拷贝字符串只会以\0结束,0x80对于字符串拷贝过程应该是一个正常的字符。
拷贝函数 于是我们找到做值拷贝的过程, 在sql/sql_string.cc的well_formed_copy_nchars中,对应的两行代码如下
res= to_cs->cset->well_formed_len(to_cs, from, from + from_length, nchars, &well_formed_error); memmove(to, from, res);
可以看到,拷贝内容时,先计算了可拷贝的长度,然后在用memmove. 调试发现,在我们上面的试验中,返回的res=1, 因此memmove就只拷贝了一个字符(a).
计算长度 于是问题出在这个to_cs->cset->well_formed_len中。 由于MySQL要支持多种字符编码,因此定义了MY_CHARSET_HANDLER (在include/m_ctype.h)中,这个结构体定义了各种编码下的特定函数接口。对应的实现实体在strings/ctyp-*.c中。 我们的例子中用到的是gbk,因此看strings/ctype-gbk.c。 上述计算长度的函数,实际上调用的是本文件中的my_well_formed_len_gbk。
static size_t my_well_formed_len_gbk(CHARSET_INFO *cs __attribute__((unused)), const char *b, const char *e, size_t pos, int *error) { const char *b0= b; const char *emb= e - 1; /* Last possible end of an MB character */ *error= 0; while (pos-- && b < e) { if ((uchar) b[0] <= 128) { /* Single byte ascii character */ b++; } else if ((b < emb) && isgbkcode((uchar)*b, (uchar)b[1])) { /* Double byte character */ b+= 2; } else { /* Wrong byte sequence */ *error= 1; break; } } return (size_t) (b - b0); }
第12行是对于英文字符的处理,第17行是对于中文字符的处理,其他的直接到第22行后判为error。我们看到,0x80就到了*error=1, 然后break。
3、 修改和小结 实际上欧元字符也可以作为单字节处理, 将上面代码的第12行改为if ((uchar) b[0] <= 128), 重新编译后执行结果如下
欧元字符在笔者客户端内显示不正常,但从hex(c)中看到三个字符已经正常存储在mysql中。 其他字符编码也有此问题,都修改相应的string/ctype-*.c中的my_well_formed_len*即可。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|||
返回顶楼 | |||
发表时间:2010-11-15
需要这么复杂吗?
将表设置为unicode存储不就完事了 |
|||
返回顶楼 | |||
发表时间:2010-11-15
最后修改:2010-11-16
murusu 写道 需要这么复杂吗?
将表设置为unicode存储不就完事了 是说utf8吗 可以试下 也有问题 而且在原有数据上改表编码需要重做数据 有别的方法也可以提出下 不过这个只是提供一种解决思路而已 |
|||
返回顶楼 | |||
发表时间:2010-11-16
把表的编码设置成unicode,然后插入没有任何问题的,已经测试过可以正常插入。
|
|||
返回顶楼 | |||
浏览 2585 次