mysql gbk2312_解决mysql gbk/gb2312时Y和~重复的问题 | moon's blog

最近整理论坛把原来的

1、问题描述

CREATETABLE`test` (`name`char(32)DEFAULTNULL) ENGINE=MyISAMDEFAULTCHARSET=DYNAMIC;

Query OK, 0rowsaffected (0.00 sec)

mysql>insertintotestvalues('YYY');

Query OK, 1 row affected (0.00 sec)

mysql>insertintotestvalues('~~~');

Query OK, 1 row affected (0.00 sec)

mysql>select*fromtestwherename='YYY';

+------+

|name|

+------+

| YYY  |

| ~~~  |

+------+

2rowsinset(0.00 sec)

aac6a25a7739c2bbade3ce9326158ced.png

上面的语句和显示结果不难看出,where name='YYY'的条件匹配到了 '~~~'

2、修改mysql源代码

解压缩mysql源码包,打开strings/ctype-gbk.c,查看sort_order_gbk这个结构体,这里是gbk的码表。可以看到第158行为” 'X', 'Y', 'Z', '{', '|', '}', 'Y', '\177',”. 这里第二个’Y’明显错误, 将其改为’~’,重新编译,执行新的mysqld,在此声明一下,我的测试环境版本为mysql-5.1.63

如果你要改

mysql>CREATETABLE`test` (`name`char(32)DEFAULTNULL) ENGINE=MyISAMDEFAULTCHARSET=gbk CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=DYNAMIC;

Query OK, 0rowsaffected (0.00 sec)

mysql>insertintotestvalues('YYY');

Query OK, 1 row affected (0.00 sec)

mysql>insertintotestvalues('~~~');

Query OK, 1 row affected (0.00 sec)

mysql>select*fromtestwherename='YYY';

+------+

|name|

+------+

| YYY  |

+------+

1rowsinset(0.00 sec)

c0d4c90a0961a14313d090588afcfc5b.png

3、原因说明

我们来分析一下strings/ctype-gbk.c的这个函数my_strnncoll_gbk_internal。当使用gbk字符时,在作字符串匹配的时候,调用此函数。

intmy_strnncoll_gbk_internal(constuchar **a_res,constuchar **b_res,

size_t length)

{

constuchar *a= *a_res, *b= *b_res;

uinta_char,b_char;

while(length--)

{

if((length > 0) && isgbkcode(*a,*(a+1)) && isgbkcode(*b, *(b+1)))

{

a_char= gbkcode(*a,*(a+1));

b_char= gbkcode(*b,*(b+1));

if(a_char != b_char)

return((int) gbksortorder((uint16) a_char) -

(int) gbksortorder((uint16) b_char));

a+= 2;

b+= 2;

length--;

}

elseif(sort_order_gbk[*a++] != sort_order_gbk[*b++])

return((int) sort_order_gbk[a[-1]] -

(int) sort_order_gbk[b[-1]]);

}

*a_res= a;

*b_res= b;

return0;

}

第9行是作中文判断的,先忽略。在我们的例子中,走的是第20行的判断。

可以看到,在判断字符值是否相同时使用sort_order_gbk[*a++] != sort_order_gbk[*b++]。当我们的*a='~', *b='Y'时,由于上面说到的158行的原因,被判定为值相同。

(作为辅助验证,如果有兴趣把第二个'Y' 改成 'Z',以后Z和~就相同了)。

4、其他解决方法

如果不改源码,也有"解决方法"

A、使用binary查询

使用binary查询后,整个字符串对照流程都与gbk无关,因此不会碰到这个bug。副作用是导致大小写敏感。

B、换字符集

从strings/目录下的各个ctype-*.c看, 只有gbk和gb2312有这个问题,因此改成utf-8,自然没有这个问题。副作用是改变了原有数据长度,且涉及到重做表。

本文地址:http://www.92csz.com/28/1168.html

如非注明则为本站原创文章,欢迎转载。转载请注明转载自:moon's blog

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值