前言
上一篇中当执行了INSERT、UPDATE or ALTER TABLE操作时,会生成对应的OK/Error包。而我们这篇要说明的是SELECT结果Result Set的解析。Result Set会涉及到了多个不同结构的包,有Column_Coun
t、Column_Def
、EOF
、Row
。
Result Set包简析
用一张图片来简单解析一下每个包的具体作用。
从上图来看,客户端发送一个select的com_query包之后,DB会按照下列步骤返回:
1.返回一个 Protocol::LengthEncodedInteger ,其中数据为column_count.(该表的显示返回中字段的个数)
2.接下来会跟column_count个Protocol::ColumnDefinition 包(对每一个字段的说明).
3.再读取一个eof包表示ColumnDefinition包流结束.
4.读取n个Row包,Row含有请求的数据值。
6.如果读到任何一个error包之后,从此读取结束,抛出错误.
7.或者你读取到了第二个eof包,按照正常顺序这里就会结束了. 但是:
如果eof包中的status & SERVER_MORE_RESULT_EXISTS不为0,表明还有ResultSet,则返回到步骤1,开始读取下一个ResultSet.
Column_count Packet
该包前四个字节表示的包的字节长度以及包的序列号。后面存放的是一个类型为LengthEncodeInteger表示结果中含有几个列。Number of fields
显示该返回字段有2列。
Column_def Packet
该包前四个字节表示的包的字节长度以及包的序列号。后四字节为以下内容。
相对包内容的位置 | 长度(字节) | 名称 | 描述 |
---|---|---|---|
0 | 不定长 | catalog | 目录,通常为def |
不定长 | 不定长 | schema | 操作的数据库 |
不定长 | 不定长 | table | 操作的虚拟表名 |
不定长 | 不定长 | org_table | 操作的物理表名 |
不定长 | 不定长 | name | 虚拟列字段名 |
不定长 | 不定长 | org_name | 物理列字段名 |
不定长 | 0x0c | length of fixed-length fields | 以下字段长度 |
不定长 | 2 | character | 列字符集 |
不定长 | 4 | length | 字段最大长度 |
不定长 | 1 | type | 字段类型 |
不定长 | 2 | flags | 标志 |
不定长 | 1 | decimals | ?? |
不定长 | 2 | 预留字节数 | 预留字节数 |
以下是Wireshark对column_def的解析截图。
EOF Packet
相对包内容的位置 | 长度(字节) | 名称 | 描述 |
---|---|---|---|
0 | 1 | 包头标识 | 0xFE 代表这是一个EOF 包 |
1 | 2 | 警告数 | 上次命令引起的警告数 |
3 | 2 | 服务器状态 | 服务器状态 |
以下是Wireshark的数据截图。
Row Packet
Row Data含着的是我们需要获取的数据,一个Result Set包里面包含着多个Row Data结构。每一个值前面有长度字节值,可以帮助我们区分开不同的列。
相对包内容的位置 | 长度(字节) | 名称 | 描述 |
---|---|---|---|
0 | 不定 | length | 这个字段的数据长度 |
不定 | 不定 | value | 这个字段的值 |
Wireshark显示Row的数据,虽然只显示了text,但是点击十六进制的数据,还是能看到length的数据。