TiDB源码阅读(二) TiDB中的MySQL协议

当 SQL 通过上一篇所描述的路径来到这里, dispatch 这个函数如它的名字一样,对不同类型的 SQL 语句 case 到不同的函数中,那咱们来看看这个函数吧,在这里:

server/conn.go

大致如下的流程

t := time.Now() 

记录时间戳 t ,记录的大概是 SQL 开始执行的时间戳。

cc.lastPacket = data

cmd := data[0]

data = data[1:]

dataStr := string(hack.String(data))


TiDB 也要根据这个格式进行解析, data[0] 就是 data 的第一个 byte ,其余的是命令。

MySQL 请求报文的命令列表

0x00 COM_SLEEP 内部线程状态

0x01 COM_QUIT 关闭连接

0x02 COM_INIT_DB 切换数据库

0x03 COM_QUERY SQL查询请求

0x04 COM_FIELD_LIST 获取数据表字段信息

0x05 COM_CREATE_DB 创建数据库

0x06 COM_DROP_DB 删除数据库

0x07 COM_REFRESH 清除缓存

0x08 COM_SHUTDOWN 停止服务器

0x09 COM_STATISTICS 获取服务器统计信息

0x0A COM_PROCESS_INFO 获取当前连接的列表

0x0B COM_CONNECT 内部线程状态

0x0C COM_PROCESS_KILL 中断某个连接

0x0D COM_DEBUG 保存服务器调试信息

0x0E COM_PING 测试连通性

0x0F COM_TIME 内部线程状态

0x10 COM_DELAYED_INSERT 内部线程状态

0x11 COM_CHANGE_USER 重新登陆

0x12 COM_BINLOG_DUMP 获取二进制日志信息

0x13 COM_TABLE_DUMP 获取数据表结构信息

0x14 COM_CONNECT_OUT 内部线程状态

0x15 COM_REGISTER_SLAVE 从服务器向主服务器进行注册

0x16 COM_STMT_PREPARE 预处理SQL语句

0x17 COM_STMT_EXECUTE 执行预处理语句

0x18 COM_STMT_SEND_LONG_DATA 发送BLOB类型的数据

0x19 COM_STMT_CLOSE 销毁预处理语句

0x1A COM_STMT_RESET 清除预处理语句参数缓存

0x1B COM_SET_OPTION 设置语句选项

0x1C COM_STMT_FETCH 获取预处理语句的执行结果

我们看一下 dispatch 接下来的部分,也就是目前 TiDB 实现的部分 MySQL 协议了。

switch cmd {

case mysql.ComPing,

mysql.ComStmtClose,

mysql.ComStmtSendLongData,

mysql.ComStmtReset,

mysql.ComSetOption,

mysql.ComChangeUser:

cc.ctx.SetProcessInfo("", t, cmd, 0)

case mysql.ComInitDB:

cc.ctx.SetProcessInfo("use "+dataStr, t, cmd, 0)

}

switch cmd {

case mysql.ComSleep:

case mysql.ComQuit:

case mysql.ComQuery:

case mysql.ComPing:

case mysql.ComInitDB:

case mysql.ComFieldList:

case mysql.ComStmtPrepare:

case mysql.ComStmtExecute:

case mysql.ComStmtFetch:

case mysql.ComStmtClose:

case mysql.ComStmtSendLongData:

case mysql.ComStmtReset:

case mysql.ComSetOption:

case mysql.ComChangeUser

default: // other not support

那我们通过 debug 尝试几个例子

create database

preview

use database

preview

create table

preview

update


delete


之后又试了 drop table 和 drop database ,同样是 cmd=3 , case=ComQuery 。

use database 比较特殊,分成了一个 cmd=3 和 2 的流程。说明先查询数据库,再 use 的。

回头看 dispatch 这部分代码,简化一下流程就是走了两遍:

1)

switch cmd { // 3

case mysql.ComQuery: //select database()

2)

switch cmd { // mysql.ComInitDB = 2

case mysql.ComInitDB

cc.ctx.SetProcessInfo("use "+ dataStr, t, cmd, 0) // 在这里拼装了use

所以这里就是先通过 select database() 查询 databases ,之后拼装 use 只用 database 。

总之,目前试了 show create table 、commit 、 rollback 、begin 、 prepare 、 show variables like 等等。

但...都是 ComQuery 。所以我们了解到, TiDB 绝大部分都是 ComQuery 。就算如此,不同 SQL 肯定是通过不同 type 进行解析执行的。

case mysql.ComQuery:

if len(data) > 0 && data[len(data)-1] == 0 {

data = data[:len(data)-1]

dataStr = string(hack.String(data))

}

return cc.handleQuery(ctx, dataStr)

于是我们仔细看看这个 case , 要去看下 cc.handleQuery(ctx , dataStr) 

func (cc *clientConn) handleQuery(ctx context.Context, sql string) (err error) {

stmts, err := cc.ctx.Parse(ctx, sql)

}

总结起来就是看 Parse ,如何做解析的。

这时候转到 

github.com/pingcap/parser@v0.0.0-20200623082809-b74301ac298b/parser.y 

会看到这里有很多的 case


根据不同的 SQL ,执行不同的 parser.y

这些也会在以后的篇幅中做介绍。


以上是 TiDB源码阅读(二) TiDB中的MySQL协议 的全部内容, 来源链接: utcz.com/a/35810.html

回到顶部