liukuan.net

liukuan.net,发现,记录,分享

259

MySQL数据结构分析—Protocol

      MySQL数据结构Protocol及相关处理方法,是MySQL服务器端遵循的协议规范。本文通过解析MySQL服务器端的协议,分析各种协议的格式,以便于更清晰的了解协议规则。

数据结构

      Protocol数据结构定义在MySQL的源码sql/protocol.h中,Protocolclass类型,派生了Protocol_textProtocol_binary两个子类,分别用于处理字符类数据和二进制数据的存储。Protocol类的关系图如下所示:

1 Protocol类关系

      Protocol类中主要的分为三类:基本参数、数据存储、数据发送。其中基本参数主要包括thdTHD数据结构,主要用于存储当前线程session的一些参数;packet是数据包字段;此外还有字段相关的变量,如field_count字段数、field_pos字段位置、field_types字段类型等。数据存储相关处理方法主要是用于处理和存储不同字段类型的数据,这些方法对不同的数据类型,可以在派生类里面进行重写。数据发送主要包括发送执行状态和发送数据等处理方法,其中在数据发送阶段是协议格式的封装过程,并且在发送数据时调用数据存储的相关处理方法,根据数据字段的类型,对数据进行封装发送。

协议格式

      协议格式部分主要从发送阶段数据格式的封装角度来诠释MySQL数据传输协议。以下将对所有的数据传输传输格式进行分析,由于客户端协议版本的问题,有些数据格式也有所不同。

error信息格式

      error信息是执行状态的一种,发送error信息,根据客户端不同的协议版本,有以下两种格式。

客户端协议4.1error信息格式:

2客户端4.1协议error信息格式

      errnoMySQL对应的错误号,2个字节存储;“#”用于将错误号与错误信息分开;sql_state表示sql执行的状态;Error
msg
表示错误信息,最大512个字节长度。其中“#”和sql_state是客户端4.1协议增加的格式。

客户端之前协议error信息格式:

3客户端之前协议error信息格式

      客户端之前的协议仅包含两个字段,错误号errno和错误信息Error
msg
。对应的字段存储结构与4.1协议一致。

Error信息传输格式:

      Error信息格式在网络层传输时,通过调用NET处理函数net_write_command()进行网络传输,传输格式如下所示:

4 error信息传输格式

      从传输格式可以看出,前三个字节存储packet的最大长度;1个字节存储下一个packet的编号;1个字节存储255,表示当前信息是错误信息,在数据信息解析过程中,用于判断是否为错误信息;ERROR内容时以上error信息格式封装的内容。特别说明的,255Error信息与其他信息的最大区别,其他信息在传输时的格式如上类似,但是没有该字段。

OK信息格式

      OK信息是SQL执行的成功状态信息,其数据格式根据客户端协议版本,有两种数据格式。

客户端协议4.1OK信息格式:

5客户端4.1协议OK信息格式

      从协议格式来看,0是一个标志位,用于表示为OK信息;affect_rowsSQL执行影响的记录行数;id为查询id值;server_status表示SQL执行后,server的状态值;warn_countSQL执行产生的警告信息数,最大值为65535,大于这个数存储65535msg表示传输的信息,没有长度限制,如果信息过长,会进行分包传输。其中warn_count是在客户端协议4.1中增加的字段。

客户端协议4.0OK信息格式:

6客户端4.0协议OK信息格式

      与协议4.1不同的是,4.0中不包含warn_count值。但是存储了server_status字段,用于记录serverSQL执行结束后的状态。

客户端之前协议OK信息格式:

7OK信息格式

      对于之前的协议,OK信息格式没有server_statuswarn_count字段,仅包含基本的SQL执行信息。

      在传输时,传输格式类似于Error传输格式,不同的是,没有单独的255字节标示错误信息。然而在传输的信息中,OK的信息格式的第一个字节标志位,与255的意义是一样的,同样是用于标示数据内容为OK信息。

EOF信息格式

      EOF信息是用于表示传输数据结束的信息,根据客户端协议的版本,该信息也有两种格式。对于客户端协议4.1之前的EOF信息格式仅仅是发送信息标示一个字节(254),对于4.1协议,格式如下所示。

客户端协议4.1EOF信息格式:

8客户端4.1协议EOF信息格式

      有信息格式可知,254标示EOF信息,在数据传输中,254信息类型为EOF信息;warn_countserver_status字段的含义与OK信息格式中的字段一致,不再赘述。

Metadata信息格式

      Metadata数据时数据库的表定义信息,主要是将数据表的各个字段进行封装,进行数据传输。Metadata信息的格式根据客户端协议的版本,也有两种格式。

客户端协议4.1Metadata信息格式:

      Metadata是对表定义的字段进行封装,以下仅将其中一个字段的详细信息格式给出,其他字段省略。

9客户端4.1协议Metadata信息格式

      由以上格式可知,首先“def”三个字符是字段定义的开始;然后db_nametable_nameorg_table_namecol_nameorg_col_name分别表示数据库名、表名、原始表名、列名、原始表名;数字12是指还需要12个字节来存储后面的字段信息;charset_num表示字符集编号;length表示字段的长度;type表示字段的数据类型;flags表示字段的标志位;decimals表示数据的精度;之后两个字节存储0,用于以后扩展。完整的一个字段存储完成后,紧接着下一个字段的定义。

客户端之前协议Metadata信息格式:

10 Metadata信息格式

      Metadata信息格式各个字段的含义是:table_namecol_name分别表示表名和字段名;3表示接下来信息占用的字节数,即length需要占用3个字节;1type含义同上;后面的3表示flagsdecimals共占用三个字节。从以上信息格式来看,metadata在之前版本中存储的格式和字段较4.1协议,存在一些不足。首先字段定义之间没有严格的分割界限;其次每个字段的长度占用一个字节去存储占用的字节数,浪费空间;最后信息内容不够全面。而这些问题,在4.1协议中有了较好的改进。

      在处理函数send_result_set_metadata()中,根据flags的值,有几种不同的处理结果。其中一个是直接获取字段数,直接传输结果;另外就是发送EOF信息,表明数据传输结束。

ROW信息格式

      ROW信息的存储根据不同字段的存储类型,存储方式也不同,以下将根据不同的字段类型,分别给出具体字段的信息格式。

字符类型的NULL存储格式

      对于字段的数据为NULL的情况,在ROW数据封装时,仅存储251,占用1个字节。即在封装的数据包中,251表示NULL值。

字符类型存储格式

      字符类型主要包括MYSQL_TYPE_NULLMYSQL_TYPE_DECIMALMYSQL_TYPE_ENUMMYSQL_TYPE_SETMYSQL_TYPE_TINY_BLOBMYSQL_TYPE_MEDIUM_BLOBMYSQL_TYPE_LONG_BLOBMYSQL_TYPE_BLOBMYSQL_TYPE_GEOMETRYMYSQL_TYPE_STRINGMYSQL_TYPE_VAR_STRINGMYSQL_TYPE_VARCHARMYSQL_TYPE_BITMYSQL_TYPE_NEWDECIMAL,这些数据类型都是以字符的方式存储,特别注意的是文本类型与字符集有紧密的关系。字符类型根据长度,存储格式有多种格式,具体如下所示:

1、数据长度小于251

      数据长度小于251时,仅存储数据长度和数据内容。其中数据长度length占用1个字符。存储格式如下所示:

11数据长度小于251的字符格式

2、数据长度大于等于251小于65536

      数据长度大于等于251并且小于65536时,存储格式包括三个部分:标志位252,表示数据长度范围;数据长度length,占用字节数与字符集有关;数据data内容。存储格式如下所示:

12数据长度小于65536的字符格式

3、数据长度大于等于65536小于16M

      数据长度大于等于65536并且小于16M时,存储格式同第二种格式类似,仅标注位和数据长度占用的字节数不同。具体存储格式如下所示:

13数据长度小于16M的字符格式

数据类型存储格式

      数据类型的存储首先调用对应的函数转化为字符类型(如tinylongfloatdecimal等类型),或者封装数据类型为字符类型(如timedatetime等)。最后处理转化为字符类型存储。

二进制数据存储格式

      二进制数据格式的存储没有字符集的问题,因此数据类型也不需要转化为字符类型,直接封装数据即可,存储格式同以上格式一致。其中对NULL值的存储格式有较大差异,存储格式根据字段位置计算,存储NULL值的源码如下所示:

 


boolProtocol_binary::store_null()

{

 uint offset= (field_pos+2)/8+1,
bit= (1 << ((field_pos+2) & 7));

 /* Room for this as it's allocated in prepare_for_send */

 char *to= (char*)
packet->ptr()+offset;

 *to= (char) ((uchar) *to | (uchar)
bit);

 field_pos++;

 return 0;

}


结论

      通过对协议中各种信息的格式进行分析,进一步了解了MySQL服务器端数据封装和传输的协议。更深入的,结合客户端传输内容,分析传输内容,进行中间代理层处理,从而达到控制命令和数据的目的。

 

原文地址 : https://liukuan.net/note/95.html
本站遵循 : 知识共享署名-非商业性使用-相同方式共享 3.0 版权协议
版权声明 : 原创文章转载时,请务必以超链接形式标明 文章原始出处
作者:admin | 分类:学习笔记,网络分享,数据库,c/c++ | 标签: Null
此文章共有条评论, 人参与 |Powerd By Angboo