论坛首页 综合技术论坛

关于MySQL中Y和~问题

浏览 1904 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-11-09   最后修改:2010-11-09

    最近在坛子里还看到说到Y~的问题,不知道mysql官方的bugs里面安排到什么时候解决这个bug。这里描述一下,说明一下原因。

 

1、              问题描述

mysql> create table t (c char(32)) engine=innodb;

Query OK, 0 rows affected (0.01 sec)

mysql> insert into t values('Y');

Query OK, 1 row affected (0.02 sec)

mysql> insert into t values('~');

Query OK, 1 row affected (0.00 sec)

mysql> select * from t where c='Y';

+------+

| c    |

+------+

| Y    |

| ~    |

+------+

2 rows in set (0.00 sec)

 

上面的语句和显示结果容易看出,where c=’Y’的条件匹配到了 ‘~’.

 

2、              源码修改

    打开strings/ctype-gbk.c,查看sort_order_gbk这个结构体,这里是gbk的码表。可以看到第157行为 'X',   'Y',   'Z',   '{',   '|',   '}',   'Y',   '\177',”. 这里第二个’Y’明显错误, 将其改为’~’,重新编译,执行新的mysqld

上述最后一个语句结果为

mysql> select *from t where c='Y';

+------+

| c    |

+------+

| Y    |

+------+

1 row in set (0.00 sec)

 

 

3、原因说明

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

 

int my_strnncoll_gbk_internal(const uchar **a_res, const uchar **b_res,
                  size_t length)
{
  const uchar *a= *a_res, *b= *b_res;
  uint a_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--;
    }
    else if (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;
  return 0;
} 

  

 

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

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

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

 

4、  其他解决方法

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

1)      使用binary查询

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

2)      换字符集

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

 

   发表时间:2010-11-25  
顶一个,学习一下!
没研究过这么深呢
0 请登录后投票
论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics