开发者社区> sea-boat> 正文

mysql 协议的错误包及解析

简介: git https://github.com/sea-boat/mysql-protocol 概况 mysql客户端与mysql服务端交互过程中,如果服务端遇到错误需要告知客户端则返回错误包。
+关注继续查看

git

https://github.com/sea-boat/mysql-protocol

概况

mysql客户端与mysql服务端交互过程中,如果服务端遇到错误需要告知客户端则返回错误包。

mysql通信报文结构

类型 名字 描述
int<3> payload长度 按照the least significant byte first存储,3个字节的payload和1个字节的序列号组合成报文头
int<1> 序列号
string payload 报文体,长度即为前面指定的payload长度

错误包

Payload

Type Name Description
int<1> header [ff] header of the ERR packet
int<2> error_code error-code
if capabilities & CLIENT_PROTOCOL_41 {
string[1] sql_state_marker marker of the SQL State
string[5] sql_state SQL State
}
string error_message human readable error message

更多详情 : http://dev.mysql.com/doc/internals/en/packet-ERR_Packet.html

错误包操作

  1. 错误包类
/**
 * 
 * @author seaboat
 * @date 2016-09-25
 * @version 1.0
 * <pre><b>email: </b>849586227@qq.com</pre>
 * <pre><b>blog: </b>http://blog.csdn.net/wangyangzhizhou</pre>
 * <p>mysql error packet.</p>
 */
public class ErrorPacket extends MySQLPacket {
    public static final byte header = (byte) 0xff;
    private static final byte SQLSTATE_MARKER = (byte) '#';
    private static final byte[] DEFAULT_SQLSTATE = "HY000".getBytes();

    public int errno;
    public byte mark = SQLSTATE_MARKER;
    public byte[] sqlState = DEFAULT_SQLSTATE;
    public byte[] message;

    public void read(byte[] data) {
        MySQLMessage mm = new MySQLMessage(data);
        packetLength = mm.readUB3();
        packetId = mm.read();
        mm.read();
        errno = mm.readUB2();
        if (mm.hasRemaining() && (mm.read(mm.position()) == SQLSTATE_MARKER)) {
            mm.read();
            sqlState = mm.readBytes(5);
        }
        message = mm.readBytes();
    }

    public void write(ByteBuffer buffer) {
        int size = calcPacketSize();
        BufferUtil.writeUB3(buffer, size);
        buffer.put(packetId);
        buffer.put(header);
        BufferUtil.writeUB2(buffer, errno);
        buffer.put(mark);
        buffer.put(sqlState);
        buffer.put(message);
    }

    @Override
    public int calcPacketSize() {
        int size = 9;// 1 + 2 + 1 + 5
        if (message != null) {
            size += message.length;
        }
        return size;
    }

    @Override
    protected String getPacketInfo() {
        return "MySQL Error Packet";
    }

} 
  1. 十六进制转换工具
/**
 * 
 * @author seaboat
 * @date 2016-09-25
 * @version 1.0
 * <pre><b>email: </b>849586227@qq.com</pre>
 * <pre><b>blog: </b>http://blog.csdn.net/wangyangzhizhou</pre>
 * <p>hex transform util.</p>
 */
public class HexUtil {
    private final static byte[] hex = "0123456789ABCDEF".getBytes();

    public static String Bytes2HexString(byte[] b) {
        byte[] buff = new byte[2 * b.length];
        for (int i = 0; i < b.length; i++) {
            buff[2 * i] = hex[(b[i] >> 4) & 0x0f];
            buff[2 * i + 1] = hex[b[i] & 0x0f];
        }
        return new String(buff);
    }

    public static String str2HexStr(String str) {
        char[] chars = "0123456789ABCDEF".toCharArray();
        StringBuilder sb = new StringBuilder("");
        byte[] bs = str.getBytes();
        int bit;
        for (int i = 0; i < bs.length; i++) {
            bit = (bs[i] & 0x0f0) >> 4;
            sb.append(chars[bit]);
            bit = bs[i] & 0x0f;
            sb.append(chars[bit]);
        }
        return sb.toString();
    }
}
  1. 错误包生成测试
/**
 * 
 * @author seaboat
 * @date 2016-09-25
 * @version 1.0
 * <pre><b>email: </b>849586227@qq.com</pre>
 * <pre><b>blog: </b>http://blog.csdn.net/wangyangzhizhou</pre>
 * <p>test auth packet.</p>
 */
public class ErrorPacketTest {
    @Test
    public void produce() {
        ErrorPacket err = new ErrorPacket();
        err.packetId = 1;
        err.errno = 32322;
        err.message = "sorry".getBytes();
        ByteBuffer buffer = ByteBuffer.allocate(256);
        err.write(buffer);
        buffer.flip();
        byte[] bytes = new byte[buffer.remaining()];
        buffer.get(bytes, 0, bytes.length);
        String result = HexUtil.Bytes2HexString(bytes);
        System.out.println(result);
        assertTrue(Integer.valueOf(result.substring(0, 2), 16) == result
                .length() / 2 - 4);

        ErrorPacket err2 = new ErrorPacket();
        err2.read(bytes);
        assertTrue(err2.errno == 32322);
        assertTrue(err2.message.length == "sorry".getBytes().length);
    }

}

========广告时间========

鄙人的新书《Tomcat内核设计剖析》已经在京东销售了,有需要的朋友可以到 https://item.jd.com/12185360.html 进行预定。感谢各位朋友。

为什么写《Tomcat内核设计剖析》

=========================

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
MySQL出现Data too long for column...(错误号1406)和 Data truncated for column...(错误号1265)
MySQL出现Data too long for column...(错误号1406)和 Data truncated for column...(错误号1265)
209 0
mysql:解压版MySQL通过SQLyog可视化密码过期问题(错误号码1862)
mysql:解压版MySQL通过SQLyog可视化密码过期问题(错误号码1862)
144 0
MYSQL 索引成本计算,为什么MYSQL预判后选择了错误索引?
IO 成本: 即从磁盘把数据加载到内存的成本,默认情况下,读取数据页的 IO 成本是 1,MySQL 是以页的形式读取数据的,即当用到某个数据时,并不会只读取这个数据,而会把这个数据相邻的数据也一起读到内存中,这就是有名的程序局部性原理,所以 MySQL 每次会读取一整页,一页的成本就是 1。所以 IO 的成本主要和页的大小有关
102 0
mysql启动提示unrecognized service错误
mysql启动提示unrecognized service错误
142 0
MySQL无法启动的问题->MySQL 服务正在启动 . MySQL 服务无法启动。服务没有报告任何错误。 请键入 NET HELPMSG 3534 以获得更多的帮助
注意以上的操作会清除数据库内容及已经创建的数据库用户,会生成一个新的用户root,此用户没有密码🐱‍🏍
146 0
【C#】【MySQL】【配置数据源】SSL Connection error 发生一个或多个错误。由于·意外的数据包格式,握手失败
【C#】【MySQL】【配置数据源】SSL Connection error 发生一个或多个错误。由于·意外的数据包格式,握手失败
52 0
安装MySQL时报由于找不到VCRUNTIME140_1.dll,无法继续执行代码。重新安装程序可能会解决此问题错误
安装MySQL时报由于找不到VCRUNTIME140_1.dll,无法继续执行代码。重新安装程序可能会解决此问题错误
220 0
Navicat连接MySQL数据库报2059错误如何解决?
Navicat连接MySQL数据库报2059错误如何解决?
60 0
mysql操作中 出现You can‘t specify target table for update in FROM clause错误的解决方法
这个错误实际上也不能称之为咱们sql语句写的不行,实际上是我们在一些细节上没有遵循mysql的语法规范。 问题所在:我们一个sql语句中先select这个表,然后再update这个表的内容。 错误示范: UPDATE StuCose SET Grade=60 WHERE Sno IN( SELECT Sno FROM stucose WHERE Grade<=ALL( SELECT MIN(Grade) FROM stucos
131 0
nivicat复制mysql数据库[Err] [Dtf] 1273 - Unknown collation: 'utf8mb4_0900_ai_ci'错误
问题的原因是两个数据库待转移的表的字符格式不能被被转移数据库识别。例如mysql8的utf8mb4_0900_ai_ci格式再mysql5中就不支持。就需要更改数据库字符编码和各个varchar等字段的编码方式
83 0
+关注
sea-boat
擅长篮球、跑步、游泳、羽毛球、编程、看书、写书的顾家好男人! Java深度、大数据、中间件、搜索引擎、机器学习、深度学习、Python、C++、开源! 《Tomcat内核设计剖析》作者。
文章
问答
视频
文章排行榜
最热
最新
相关电子书
更多
高效MySQL的N个习惯
立即下载
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
相关镜像