本文说明一下MySQL中不支持欧元字符的原因及解决方法。
1、 问题描述
在mysql中插入的字符串中若包含欧元字符(€),会发现该字符及以后的字符串都变得“不可见”。实际上这里并非不可见,而是根本没有进入数据库中。简单描述步骤如下:
root@test 05:15:41>create table t(c char(32)) engine=innodb charset=gbk;
Query OK, 0 rows affected (0.01 sec)
root@test 05:16:29>insert into t values(concat('a', char(128), 'b'));
Query OK, 1 row affected, 1 warning (0.00 sec)
root@test 05:17:04>select * from t;
+------+
| c |
+------+
| a |
+------+
|
可以看到,我们试图插入三个字符(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), 重新编译后执行结果如下
mysql> insert into t values(concat('a', char(128), 'b'));
Query OK, 1 row affected (0.00 sec)
insert select hex(c) from t;
+--------+
| hex(c) |
+--------+
| 618062 |
+--------+
|
欧元字符在笔者客户端内显示不正常,但从hex(c)中看到三个字符已经正常存储在mysql中。
其他字符编码也有此问题,都修改相应的string/ctype-*.c中的my_well_formed_len*即可。
分享到:
相关推荐
mysql解析Json字符串插件 安装方法 1、拷贝lib_mysqludf_json_parsing.dll到mysql目录C:\Program Files\MariaDB 5.5\lib\plugin下 2、在数据库中执行 DROP FUNCTION json_get; CREATE FUNCTION json_get RETURNS ...
虽然MySQL的正则表达式支持相对较弱,但仍然可以用来进行复杂的字符串处理。`REGEXP_SUBSTR()`或`REGEXP_REPLACE()`等函数可以帮助我们实现更灵活的分割。例如,通过正则表达式匹配并提取特定模式的子串。 五、JSON...
### 一、理解MySQL字符集 在深入探讨修改字符集的方法之前,我们首先需要了解MySQL中的字符集概念。字符集是指一系列字符及其编码方式的集合。在MySQL中,常用的字符集有`latin1`、`utf8`等。其中: - **`latin1`*...
### MySQL 计算字符串相似度 #### 背景与需求 在许多应用场景中,我们需要对两个字符串进行相似度比较,比如搜索引擎中的关键词匹配、文本分析中的近义词识别等。MySQL 提供了多种方法来实现字符串相似度的计算,...
### MySQL字符集转换详解 #### 一、引言 在MySQL数据库管理中,字符集的正确设置至关重要。它直接影响到数据的存储与检索效果,尤其是对于包含多种语言文本的应用场景而言。本文将围绕“MySQL字符集转换”这一主题...
MySQL 字符集查看和修改 MySQL 字符集是 MySQL 数据库中最重要的配置之一,它影响着数据库的字符存储和比较方式。本文将介绍如何查看和修改 MySQL 字符集。 查看 MySQL 字符集 要查看 MySQL 字符集,可以使用 ...
### MySQL字符集的基本概念 字符集(Character Set)定义了数据在存储和处理时所采用的编码标准,而校对集(Collation)则规定了字符集下的排序规则和比较方式。在MySQL中,主要涉及以下几个关键变量: - `...
本文将详细探讨“MySQL_MySQL字符集互转”这一主题,以及如何利用工具如"MSSQL2MySQLSync"进行数据库之间的转换与同步。 MySQL是一种广泛使用的开源关系型数据库管理系统,其支持多种字符集,包括UTF-8、GBK等。...
亲测可用,mysql字符串相似度匹配函数。下载后直接在mysql中可以测试运行。
标题中的“PB通过连接字符串连接MySQL”指的是使用PowerBuilder(PB)这个开发工具,通过特定的连接字符串来与MySQL数据库建立连接。PowerBuilder是Sybase公司(现为SAP的一部分)开发的一种可视化、面向对象的编程...
查看mysql字符集MySQL 乱码的根源是的 MySQL 字符
MySQL 批量修改SCHEMA下所有数据表的编码及字符集
利用mysql中提供的所有函数,组成的一个存储过程。此存储过程主要是将传入的字符串分割为多个值,单个列。
MySQL字符集设置是数据库管理中的一个重要环节,尤其是在处理多语言数据或者有特殊字符需求的应用中。字符集决定了数据库、表以及字段如何存储和显示字符,影响到数据的正确性及兼容性。以下将详细讲解MySQL字符集的...
1. 多语言支持:MySQL 5.5支持多种字符集,包括ASCII、UTF-8、GBK等,以满足不同语言环境的需求。UTF-8是最常用的一种,它可以存储世界上大部分语言的字符。 2. 全局字符集:全局字符集设置在my.cnf配置文件中,...
本篇文章将详细介绍不同类型的MySQL连接字符串及其用法。 首先,我们来看MySQL Connector/ODBC的连接方式。ODBC(Open Database Connectivity)是一种通用数据库访问接口,它允许应用程序通过ODBC驱动程序连接到...
Linux 修改 MySQL 字符集 在 Linux 系统中,MySQL 的字符集默认为 latin1,然而在某些情况下,我们需要修改 MySQL 的字符集以确保某些迁移的程序可以正常显示。在本文中,我们将介绍如何在 Linux 下修改 MySQL 的...