也是一种com_query包,如下图所示: ? ##2.DB向Client返回Okay包 Okay包已经在之前的博客中讲述过,在此不再赘述。 ##3.Client向DB发送SQL语句 SQL语句即是Com_query包,如果是insert、update或者delete则返回okay包。 Commit/Rollback报文 Commit/Rollback报文也是一种com_query报文,如下图所示: ? Commit报文发送后,DB进行事务提交,并返回okay报文。
如果你看了 上一章 , 那你应该就明白了Mysql连接的时候都干了啥, 但是光连上也没啥用啊, 要发送SQL,接收server发来的数据.本文主要就讲mysql客户端服务端发送数据过程(仅COM_QUERY )发送SQL(COM_QUERY)发送sql比较简单, 直接就是 包头加sql就行了....名字大小(字节)描述payload_length3包大小sequence_id1序列号,每个com都重置为0com_query10x03sql 剩余的大小sqlbdata = struct.pack('<IB',len(sql)+1,0x03) #I:每个com_query的seq_id都从0开始,第4字节固定为0, 所以直接用I, +1:com_query (0x03):1 sql:nbdata = struct.pack('<IB',len(sql)+1,0x03) #I:每个com_query的seq_id都从0开始,第4字节固定为0, 所以直接用I, +1:com_query占用1字节, 0x03:com_querybdata += sql.encode()self.sock.sendall(bdata)self.
MySql 客户端使用 COM_QUERY 发出的请求,MySql 服务端会以文本协议响应结果;使用 COM_STMT_EXECUTE 命令发出的请求,会以二进制协议响应结果。 available_qty - 2, allocated_qty = allocated_qty + 2 where product_sysno = 1 and available_qty >= 2;通过 COM_QUERY dotnet core 使用 COM_QUERY 提交请求自然无法协调分布式事务,在 v0.1.1 我们增加了 COM_QUERY 请求协调分布式事务的支持,这样真正做到了支持所有微服务语言协调分布式事务
default db: server username : larry in_trans : false in_calc_found : false COM_QUERY default db: server username : larry in_trans : false in_calc_found : false COM_QUERY default db: server username : larry in_trans : false in_calc_found : false COM_QUERY db: larrydb server username : larry in_trans : false in_calc_found : false COM_QUERY db: larrydb server username : larry in_trans : false in_calc_found : false COM_QUERY
MySql协议详解-CRUD与Result篇 Com_query报文 一般对DB的CRUD操作都由com_query报文封装并发送给DB。com_query报文如下图所示: ? 从上图中可以看到,当客户端发送一个select的com_query包后,DB会按照下列步骤返回: Step1:返回一个ResultSetHeader报文,其中包含了fieldCount,在此图就不例出了
default db: server username : larry in_trans : false in_calc_found : false COM_QUERY larrydb server username : larry in_trans : false in_calc_found : false COM_QUERY larrydb server username : larry in_trans : false in_calc_found : false COM_QUERY larrydb server username : larry in_trans : false in_calc_found : false COM_QUERY larrydb server username : larry in_trans : false in_calc_found : false COM_QUERY
= nil { 可以看到它是一个单独的命令,mysql的命令列表如下: const ( COM_SLEEP byte = iota COM_QUIT COM_INIT_DB COM_QUERY 执行的过程就是向server发送COM_QUERY命令 func (c *Conn) exec(query string) (*Result, error) { if err := c.writeCommandStr (COM_QUERY, query); err !
COM_QUERY/COM_STMT_PREPARE中多条语句CLIENT_MULTI_RESULTS = 1 << 17 #multi-resultsCLIENT_PS_MULTI_RESULTS = 客户端能处理可选元数据信息CLIENT_ZSTD_COMPRESSION_ALGORITHM = 1 << 26 #zstd压缩CLIENT_QUERY_ATTRIBUTES = 1 << 27 #支持COM_QUERY
包体其中包头由3字节的payload_length和1字节的seq组成, 而不同的包, 包体都不一样,但通常第一字节都为包类型.连接过程的包如下:SQL包而我们本次需要改写的则是SQL包, 对应为: COM_QUERY COM_QUERY/COM_STMT_PREPARE中多条语句CLIENT_MULTI_RESULTS = 1 << 17 #multi-resultsCLIENT_PS_MULTI_RESULTS = 客户端能处理可选元数据信息CLIENT_ZSTD_COMPRESSION_ALGORITHM = 1 << 26 #zstd压缩CLIENT_QUERY_ATTRIBUTES = 1 << 27 #支持COM_QUERY 包结构如下:对象大小描述pack_header4包头type1包类型, 0x03表示com_querysqlnsql语句当有CLIENT_QUERY_ATTRIBUTES的时候的COM_QUERY包结构如下 read_pack(rf) #print(bdata[4:]) if bdata[4:5] == b'\x03': # COM_QUERY
在执行use dbname, 有时候卡的时候能看到这个状态 3 COM_QUERY Query COM_CREATE_DB Create DB 没见过, create database语句是使用的COM_QUERY COM_DROP_DB Drop DB 没见过,drop database语句是使用的COM_QUERY 7 COM_REFRESH Refresh 5.7.11就移除了,现在是走COM_QUERY 8 COM_DEPRECATED_1 Shutdown 走COM_QUERY
COM_QUERY枚举值 // A list of all MySQL protocol commands // These are the top level commands the server // COM_QUERY为mysql_real_query对应的命令字 COM_QUERY // See @ref page_protocol_com_query 。。。。。。 DBUG_RETURN(simple_command( mysql, COM_QUERY, (uchar *)query, length, 1)); // 最后一个参数值1表示跳过检查 } 9. simple_command 只有发包,并没有收包, // 而且没有发现有设置错误码ER_NET_PACKET_TOO_LARGE的地方 if (net_write_command( net, (uchar)command, // COM_QUERY NET_HEADER_SIZE + 1; // 5字节 // buff的第5个字节 // For first packet buff[4] = command; // 命令字(对于mysql_real_query值为COM_QUERY
在我们的 intercept 函数中,我们执行以下操作: 查找 COM_QUERY 客户端命令,其数字代码为 3。 获取原始查询。 进行非常基本的表重命名。 main.go const COM_QUERY = byte(0x03) func intercept(src, dst net.Conn) { buffer := make([]byte, 4096 ) for { n, _ := src.Read(buffer) if n > 5 { switch buffer[4] { case COM_QUERY:
query(self,sql): """不考虑SQL超过16MB情况""" # payload_length:3 sequence_id:1 payload:N # payload: com_query (0x03):1 sql:n bdata = struct.pack('<IB',len(sql)+1,0x03) #I:每个com_query的seq_id都从0开始,第4字节固定为0, 所以直接用 I, +1:com_query占用1字节, 0x03:com_query bdata += sql.encode() self.sock.sendall(bdata) self.
比较简单, 如果要使用caching_sha2_password, 可以参考我之前的文章为了兼容mysql客户端, 我们需要解析一些特殊的包init_db use database 时用的(0x02)com_query Definition 客户端请求表字段的包(0x04)OK 就是ok包(0x00或者0xFE)ERROR 有问题的时候,就发送error包(0xFF)EOF 5.7.5之后使用OK包代替 (0xFE)我们主要看com_query Exception as e:rowpack = [ mysqlpack.errorpack(6668,str(e).encode()) ]finally:cursor.close()#print('COM_QUERY
,第一个 byte 即为 Command 的类型: 580: cmd := data[0] 然后根据 Command 的类型,调用对应的处理函数,最常用的 Command 是 COM_QUERY ,对于大多数 SQL 语句,只要不是用 Prepared 方式,都是 COM_QUERY,本文也只会介绍这个 Command,其他的 Command 请读者对照 MySQL 文档看代码。 读者可以参考 MySQL 协议中的 COM_QUERY Response 理解这段代码。 接下的几节我们进入核心流程,看看一条文本的 SQL 是如何处理的。
UseDB(dbName string) error //handle COM_QUERY command, like SELECT, INSERT, UPDATE, etc... interface{} { switch cmd { case COM_QUIT: c.Close() c.Conn = nil return noResponse{} case COM_QUERY
auth_pack)def query(self,sql):"""不考虑SQL超过16MB情况"""# payload_length:3 sequence_id:1 payload:N# payload: com_query (0x03):1 sql:nbdata = struct.pack('<IB',len(sql)+1,0x03) #I:每个com_query的seq_id都从0开始,第4字节固定为0, 所以直接用I, +1:com_query占用1字节, 0x03:com_querybdata += sql.encode()self.sock.sendall(bdata)self.
3217 #1 0x000000000329ddaa in dispatch_command (thd=0x7f7d6000dcb0, com_data=0x7f7dc43f1a00, command=COM_QUERY 1661 #2 0x000000000329dff7 in dispatch_command (thd=0x7f7d6000dcb0, com_data=0x7f7dc43f1a00, command=COM_QUERY
3217#1 0x000000000329ddaa in dispatch_command (thd=0x7f7d6000dcb0, com_data=0x7f7dc43f1a00, command=COM_QUERY 1661#2 0x000000000329dff7 in dispatch_command (thd=0x7f7d6000dcb0, com_data=0x7f7dc43f1a00, command=COM_QUERY
enum_server_command command, const char *packet, uint packet_length) { switch (command) { case COM_QUERY 它根据不同的命令类型(如COM_QUERY)调用相应的处理函数。check_access:这个函数负责检查用户是否有权限执行特定的操作。