`
丁林.tb
  • 浏览: 797232 次
  • 性别: 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  
顶一个,学习一下!
没研究过这么深呢

相关推荐

    Linux中安装MySQL遇到的各种坑

    查看目前系统中关于 mysql 存在可以升级和安装的安装包。 然后,可以使用以下命令安装 MySQL: yum -y install mysql-server mysql mysql-devel 解决依赖关系 在安装 MySQL 时,可能会出现依赖关系问题。可以...

    Mysql 5.1 中文手册

    MySQL是一个广泛使用的开源关系型数据库管理系统(RDBMS),它以其高效、稳定和易于管理的特点,在Web开发和其他数据存储应用中占有重要地位。这份中文手册是英文原版的翻译版本,虽然可能不包含最新的更新,但对于...

    远程连接MySQL所遇到的问题以及解决问题方法

    远程连接MySQL所遇到的问题以及解决问题方法 在 Linux 系统中,使用 YUM 命令安装 MySQL 后,需要进行一系列的配置以便能够远程连接 MySQL 数据库。以下是解决不能进行远程连接 MySQL 数据库的问题的方法,这些方法...

    MySQL中的data文件

    在Windows系统中,这个目录通常位于MySQL的安装路径下,例如"C:\ProgramData\MySQL\MySQL Server X.Y\Data",其中X.Y代表MySQL的版本号。在Linux系统中,数据目录可能位于"/var/lib/mysql"或用户指定的其他位置。 ...

    一台主机安装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

    在IT行业中,数据库管理和编程是不可或缺的部分,而MySQL作为一个广泛使用的开源关系型数据库管理系统,其与C++的结合使用能够实现高效的数据操作。本篇将详细介绍如何在C++项目中利用mysql++库来调用MySQL数据库,...

    MySQL中创建用户及授权

    在 MySQL 中创建用户有两种方法:使用 CREATE USER 命令和使用 GRANT 命令。 使用 CREATE USER 命令 CREATE USER 命令用于创建新的 MySQL 账户。要使用 CREATE USER,您必须拥有 mysql 数据库的全局 CREATE USER ...

    yum安装和更新mysql

    在Linux环境中,使用`yum`(Yellowdog Updater Modified)工具来安装和更新MySQL数据库是非常常见的做法。`yum`是Red Hat系列Linux发行版(包括CentOS、Fedora等)中的软件包管理器,它能够帮助用户轻松地安装、更新...

    Mysql依赖jar包

    例如,`mysql-connector-java-5.x.y.jar` 适用于MySQL 5.x版本,`mysql-connector-java-8.x.y.jar` 适用于MySQL 8.x版本。不同的版本可能支持不同的功能和API,因此,选择与数据库服务器版本兼容的驱动至关重要,以...

    linux安装mysql(实测没问题)

    - 如果在安装过程中遇到 `-bash:wget: command not found` 错误,说明系统尚未安装 wget 工具,可以通过 `yum -y install wget` 命令安装 wget。 - 检查本地是否已经安装了 MySQL,可以通过命令 `rpm -qa | grep ...

    Linux中快速安装mysql5.6、MySQL5.7 以及重置密码

    对于MySQL5.7的安装,需要四个RPM包:`mysql-community-common-5.7.x.y.rpm`、`mysql-community-libs-5.7.x.y.rpm`、`mysql-community-client-5.7.x.y.rpm`和`mysql-community-server-5.7.x.y.rpm`。这里的x.y代表...

    MySQL无法安装的解决方案

    在遇到“MySQL无法安装的解决方案”这个问题时,通常是因为在重装或升级MySQL过程中,旧的服务残留在系统中,导致新安装的MySQL无法创建...在问题排查过程中,了解MySQL的安装流程和系统服务管理知识是非常有帮助的。

    CentOS6.5安装mysql5.5.37

    在本文中,我们将详细介绍如何在 CentOS6.5 操作系统上安装 MySQL5.5.37。由于 MySQL 是一个非常流行的关系型数据库管理系统,因此了解如何安装和配置 MySQL 是非常重要的。 卸载旧版本 在安装 MySQL 之前,我们...

    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-...

    龙蜥anolis8系统安装mysql5.7

    在本文中,我们将详细探讨如何在龙蜥Anolis8操作系统上安装MySQL 5.7数据库。...在整个过程中,`mysql离线安装.txt`可能包含了更详细的步骤或者解决特定问题的提示,记得参考该文档以确保顺利完成安装。

    linux-mysql5.6.29

    3. MySQL Devel: 提供了开发所需的头文件和库文件,方便开发者在C/C++等语言中编写与MySQL交互的应用程序。 二、安装MySQL 5.6.29 在Linux系统中,安装MySQL 5.6.29 RPM包通常分为以下几个步骤: 1. 更新系统包...

    linux中mysql二进制资源包安装全过程附mysql安装包

    本文将详细介绍如何在Linux(包括CentOS 6、CentOS 7、RHEL 6和RHEL 7)上安装MySQL的二进制资源包,同时也会提供解决安装过程中可能出现的问题的策略。 首先,我们需要理解Linux发行版的包管理器,如CentOS/RHEL中...

    对比MySQL中int、char以及varchar的性能

    总的来说,MySQL中的int、char和varchar在性能上的差异并非显著到足以成为决定性因素。开发者应根据实际需求,如数据的类型、大小、预期的增长、是否需要索引以及对可读性和可维护性的要求,来综合考虑选择哪种数据...

Global site tag (gtag.js) - Google Analytics