TiDB源码阅读(二) TiDB中的MySQL协议
当 SQL 通过上一篇所描述的路径来到这里, dispatch 这个函数如它的名字一样,对不同类型的 SQL 语句 case 到不同的函数中,那咱们来看看这个函数吧,在这里:
server/conn.go
大致如下的流程
t := time.Now()
记录时间戳 t ,记录的大概是 SQL 开始执行的时间戳。
cc.lastPacket = datacmd := 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
use database
create table
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