`
丁林.tb
  • 浏览: 791047 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

关于MySQL中Y和~问题

阅读更多

    最近在坛子里还看到说到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,自然没有这个问题。副作用是改变了原有数据长度,且涉及到重做表。

 

分享到:
评论
2 楼 nofreezou 2012-09-21  
LZ要先说一下mysql什么版本,我在mysql5.1.54上测试是没有这个问题的


另外再请教一个问题,strings/ctype-gbk.c 里面gbk转unicode的编码不全,这个bug为啥没人提呢?  如 static uint16 tab_gbk_uni0[]的最后,很多都是0,但是真正的gbk编码后面的还是有值的 如过set names gbk,添加到一个utf8的表里面,这样的字符就丢失了

另外有空希望LZ再写些文章介绍下源代码相关的事~~比如里面很多奇怪的变量名、文件名
1 楼 babaoqi 2010-11-25  
顶一个,学习一下!
没研究过这么深呢

相关推荐

    一台主机安装MariaDB与MySQL同时运行

    MySQL集群(一台主机安装MariaDB与MySQL同时运行) 以下是在已安装MySQL的情况下,安装MariaDB的主要步骤. [root@mariadb-near-mysql ~]# cat /etc/issue CentOS release 6.2 (Final) [root@mariadb-near-...

    C++使用mysql++y调用mysql的Demo

    C++使用mysql++y调用mysql的例子

    Mysql 5.1 中文手册

    这是MySQL参考手册的翻译版本,关于MySQL参考手册,请访问:dev.mysql.com。 原始参考手册为英文版,与英文版参考手册相比,本翻译版可能不是最新的。

    linux下mysql的rpm安装包

    yum -y remove mysql-libs-5.1.52-1.el6_0.1.i686 卸载二: 输入: #rpm -qa | grep -i mysql 显示: MySQL-client-5.1.62-1.glibc23.i386 MySQL-server-5.1.62-1.glibc23.i386 卸载方法: #rpm -ev MySQL-client-...

    MySQL无法安装的解决方案

    最近在维护服务器的时候,突然发现MySQL无法使用了,于是在“控制面板”-添加/删除程序“中删除了MySQL,重启了一下服务器再安装MySQL。 本来以为可以一路很顺利地Next下去的,但是事与愿违。运行“MySQL Server ...

    MySQL日志y.pdf

    MySql完整教程笔记

    非MySQL安装MySQL-python

    非MySQL安装MySQL-python,有时不是数据库为封装的MySQL时,可以通过yum -y install mysql-devel 但有时不行,这是可按文档去更改MySQL-python

    Mysql安装Linux

    yum -y remove mysql-libs-5.1.52-1.el6_0.1.i686 卸载二: 输入: #rpm -qa | grep -i mysql 显示: MySQL-client-5.1.62-1. glibc23.i386 MySQL-server-5.1.62-1.glibc23.i386 卸载方法: #rpm -ev MySQL-client-...

    mysql的日期和时间函数

     在 MySQL 3.23 中,如果表达式的右边是一个日期值或一个日期时间型字段,你可以使用 + 和 - 代替 DATE_ADD() 和 DATE_SUB()(示例如下)。 参数 date 是一个 DATETIME 或 DATE 值,指定一个日期的...

    mysql数据库CPU高,实时抓住数据库执行中的SQL语句,shell工具(支持mysql5.7)

    #适用于实时查询mysql占用CPU高的语句,循环监控mysql进程情况,当CPU大于一定的前执行中的SQL情况. #执行前,修改ENV认证部分 #编写:Chaoren #2022年3月4日18:38:53 # #对于执行时间非常短的SQL可能监控到的语句...

    centos中mysql下载安装.docx

    在centos如何安装MySQL 1.Rpm -qa | grep mysql -------查看是否安装了mysql 2.Yum -y install mysql----卸载无关组件 新手博主上传,请见谅

    Linux下MYSQL每天完全备份

    利用crontab,系统每天定时备份mysql数据库 利用系统crontab来定时执行备份文件,按日期对备份结果进行保存,达到备份的目的。 1、创建保存备份文件的路径/mysqldata #mkdir /mysqldata 2、创建/usr/sbin/...

    在mysql中将字符串日期转为日期型

    在mysql中使用SELECT STR_TO_DATE()函数将字符串日期转为日期型: SELECT STR_TO_DATE('2012~8~8 14.58.09','%Y~%m~%d %k.%i.%s' ); STR_TO_DATE('2012-8-8 14:58:09','%Y-%m-%d %k:%i:%s' ) A;;STR_TO_DATE('...

    xtrabackup_libaio_mysql自动备份脚本_源码

    /bin/sh#使用前安装yum -y install perl-DBD-MySQL perl-Digest-MD5 perl-DBI libev#yum install perl perl-devel libaio libaio-devel perl-Time-HiRes perl-DBD-MySQL -y#yum -y install rsync perl l perl-Digest...

    MySQL与Oracle的语法区别详细对比

    Oracle和mysql的一些简单命令对比 1) SQL> select to_char(sysdate,’yyyy-mm-dd’) from dual; SQL> select to_char(sysdate,’hh24-mi-ss’) from dual; mysql> select date_format(now(),’%Y-%m-%d’); mysql> ...

    linux下装mysql

    安装MySQL。 [root@sample ~]# yum -y install mysql-server ← 安装MySQL [root@sample ~]# yum -y install php-mysql ← 安装php-mysql

    MySQL中文拼音数据库(6565字,全拼+首字母(大小写均有))

    MySQL中文拼音数据库(6565字,全拼+首字母(大小写均有)) 里面的文件内容大体是这个样子的。(压缩包中包含sql文件,可以直接导入) INSERT INTO `hs_pinyin` VALUES (3, '在', 'zai', 'z', 'Z'); INSERT INTO `...

    mysql-8.0.33-linux-glibc2.12-x86-64.tar.xz

    MySQL 企业版审计功能使用“mysql”系统数据库存储过滤条件和用户的账户数据,为了增加灵活性,此版本增添了一个“audit_log_database”服务器系统变量,在服务器启动时可以指定到其他的数据库。 MySQL 企业版数据...

    CentOS 7.0编译安装cmake和mysql安装包

    一、安装MySQL 1、安装cmake cd /usr/local/src tar zxvf cmake-2.8.11.2.tar.gz cd cmake-2.8.11.2 ./configure make make install 2、安装MySQL groupadd mysql #添加mysql组 useradd -g mysql mysql -s...

    MySql用DATE_FORMAT截取DateTime字段的日期值

    您可能感兴趣的文章:MySQL中日期比较时遇到的编码问题解决办法PHP以及MYSQL日期比较方法mysql 获取当前日期函数及时间格式化参数详解mysql unix准换时间格式查找指定日期数据代码MySql日期查询语句详解深入mysql ...

Global site tag (gtag.js) - Google Analytics