#MySQL#

字符集实现

DATABASE MANAGEMENT

X侦探所事件簿

在前面的文章《X侦探所事件簿系列二 —— 关于字符集的秘密》中我们探索了MySQL字符集在CentOS系统下字符集变量作用和意义。这次,我们以5.7.36版本作为演示版本,探索一下MySQL内部字符集的实现,以此来从内部的视角来看看神秘的MySQL字符集是如何实现的,为源码爱好者提供一个简单的入门级接触。

#字符集相关系统表#

首先我们要了解MySQL的两个系统表,这两个表是在information_schema下,保存着charset相关信息的表(实际上在该schema下存在3个和charset相关的表,但记录重要信息的只有两个),他们分别是CHARACTER_SETS和COLLATIONS,前者是用于描述MySQL所支持的字符集及其信息,后者用于描述每个字符集所支持的字符排序规则(collation)。

CHARACTER_SETS

通过描述CHARACTER_SETS的建表元信息,我们得到如下相关信息。

其中字段的含义是如下:

这里我们看看一看GB2312这几个字符集在这个表中的内容,其他的字符集读者可以自己探索了解一下。

COLLATIONS

我们再看看COLLATIONS这张表,其定义如下:

其字段的含义如下:

这里我们看看一看GB2312这个字符集在这个表中的保存的内容:

小结

在这,留下一个疑问,为什么GB2312这个字符集,在CHARACTER_SETS有一条记录,在COLLATIONS这张表中有两条记录?我们期待读者能给出自己的答案。

#字符集实现代码#

看完这两张表的定义和表中存储的数据,就可以根据这些信息了解一下MySQL内部的实现。首先我们要了解的是用于保存字符集信息的结构CHARSET_INFO。

基本结构

在该结构中,保存了MySQL字符集所需的信息,包括charset的名字(诸如GB2312等)、charset在MySQL中的编号等。

知道有了CHARSET_INFO保存字符集信息,通过该结构,我们可以发现在这里,MySQL通过all_charsets存储支持的所有字符集(排序规则),通过default_charset_info来保存默认的字符集。

字符集的初始化

如上节找到字符集的存储对象,我们可能需要知道这些对象是如何被初始化的。因为通过了解初始化的过程可以知道charset的信息来源。

在如下函数中我们可以看到all_charsets变量被初始化为0,那么极有可能在后续的操作中将被初始化为对应的字符集信息。

对该函数内的语句的浏览,我们发现在如下函数系列中,有疑似对各个字符集变量的初始化操作。

在该函数中使用各个不同的CHARSET_INFO对象。

在add_compiled_collation函数中将传入的CHARSET_INFO对象初始化到指定all_charsets的数组中的指定位置。

通过如上这三个函数我们知道all_charsets变量的初始化是通过一个个具体的charset对象完成,那么代码看到这里就会有个疑问,类似my_charset_latin1_german2_ci的变量是哪里来初始化的呢?

在进入到strings的源码目录我们会发现如下文件,这些文件中的代码将会提供答案给我们。

探索这些文件就会发现my_charset_latin1_german2_ci是在ctype-latin1.c源码文件中做了初始化变量的操作,这是一个全局变量的初始化。在这里初始化了字符集名字,字符集排序规则名字(collation name)以及相关的重要信息。

小结

至此,我们介绍了字符集的初始化。但是,这里会有一个疑问,为什么一个字符集结构CHARSET_INFO要初始化多次?比如GB2312要初始化my_charset_big5_chinese_ci和my_charset_big5_bin两个变量?这就和前面提到collation有关了(也就是在字符集的系统中小结提到的问题)。这部分的对应关系我们留给读者自己探索,以期望读者能自己更进一步掌握相关的概念和源码。

连接时的字符集设置

以上讲了字符集在MySQL实例启动的初始化,我们再讲一下MySQL的client在连接时的字符集的问题。

在上图的MySQL通讯协议中,我们可以看到握手消息中有charset的信息,那么我们就从这里作为着手点进行代码的浏览。

首先在parse_client_handshake_packet函数中,我们找到这个charset的读取和使用位置,在41的协议版本下,我们通过读取一个字节的无符号整数得到字符集编码charset_code。

然后在定位这里通过charset_code来初始化连接的client charset,以下是对应的函数调用。

最终在这里,通过get_charset获取到字符集信息后,完成连接对象的字符集信息设置。

#总结#

至此,我们从外部了解描述MySQL字符集元信息的系统表,从内部介绍了字符集信息的入门级别源码,这两者可以帮助读者从0基础入门字符集的源码学习。在未来我们会分享更多入门级别的源码帮助揭开MySQL的源码面纱。

-END-

文章来源于腾讯云开发者社区,点击查看原文