前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >[pymysqlbinlog] TABLE_MAP_EVENT

[pymysqlbinlog] TABLE_MAP_EVENT

原创
作者头像
大大刺猬
发布2024-04-24 11:36:17
发布2024-04-24 11:36:17
16360
代码可运行
举报
文章被收录于专栏:大大刺猬大大刺猬
运行总次数:0
代码可运行

导读

本来打算table_map_event和row_event一起写的. 但table_map_event的信息还是太多了, 就先写一部分. 其实之前有提过的 https://www.modb.pro/db/1763358489816174592

但现在要系统的更新下, 尽量更完善.

table_map_event 是在row event前面的, 主要是记录元数据信息的, 比如库名,表名,字段类型等

TABLE_MAP_EVENT

5.7 版本和8.0 版本是存在区别的, 8.0 新增了opt optional metadata fields 来描述更多信息, 比如符号之类的

先看下结构吧

对象

大小(字节)

描述

table_id

6

表id

flags

2

dbname_length

1

库名字长度

dbname

dbname_length

库名(\x00结尾, 不计入length)

tablename_length

1

表名字长度(表名长度限制64字节)

table_name

tablename_length

表名字(\x00结尾, 不计入length)

column_count

pack_int

字段数量

column_type

column_count

字段类型, 每个字段使用1字节表示

metadata_length

pack_int

元数据信息长度

metadata

metadata_length

元数据信息

null_bits

int((self.column_count+7)/8)

是否允许为空

opt

tlv

8.0新增的

pack_int

先来看看 pack_int 其实之前讲过, 变长类型

代码参考:

代码语言:python
代码运行次数:0
复制
        # @mysys/pack.cc net_field_length_size
        def read_net_int(self,):
                """
                1 3 4 9 (不含第一字节)
                """
                data = self.read_uint(1)
                if data < 251:
                        return data
                elif data == 251:
                        return self.read_uint(1)
                elif data == 252:
                        return self.read_uint(2)
                elif data == 253:
                        return self.read_uint(3)
                else:
                        return self.read_uint(8)

column_type

字段类型. 先看看吧

代码语言:python
代码运行次数:0
复制
# @include/field_types.h
MYSQL_TYPE_DECIMAL      = 0
MYSQL_TYPE_TINY         = 1
MYSQL_TYPE_SHORT        = 2
MYSQL_TYPE_LONG         = 3
MYSQL_TYPE_FLOAT        = 4
MYSQL_TYPE_DOUBLE       = 5
MYSQL_TYPE_NULL         = 6
MYSQL_TYPE_TIMESTAMP    = 7
MYSQL_TYPE_LONGLONG     = 8
MYSQL_TYPE_INT24        = 9
MYSQL_TYPE_DATE         = 10
MYSQL_TYPE_TIME         = 11
MYSQL_TYPE_DATETIME     = 12
MYSQL_TYPE_YEAR         = 13
MYSQL_TYPE_NEWDATE      = 14        #/**< Internal to MySQL. Not used in protocol */
MYSQL_TYPE_VARCHAR      = 15
MYSQL_TYPE_BIT          = 16
MYSQL_TYPE_TIMESTAMP2   = 17
MYSQL_TYPE_DATETIME2    = 18        #/**< Internal to MySQL. Not used in protocol */
MYSQL_TYPE_TIME2        = 19        #/**< Internal to MySQL. Not used in protocol */
MYSQL_TYPE_TYPED_ARRAY  = 20        #/**< Used for replication only */
MYSQL_TYPE_INVALID      = 243
MYSQL_TYPE_BOOL         = 244       #/**< Currently just a placeholder */
MYSQL_TYPE_JSON         = 245
MYSQL_TYPE_NEWDECIMAL   = 246
MYSQL_TYPE_ENUM         = 247
MYSQL_TYPE_SET          = 248
MYSQL_TYPE_TINY_BLOB    = 249
MYSQL_TYPE_MEDIUM_BLOB  = 250
MYSQL_TYPE_LONG_BLOB    = 251
MYSQL_TYPE_BLOB         = 252
MYSQL_TYPE_VAR_STRING   = 253
MYSQL_TYPE_STRING       = 254
MYSQL_TYPE_GEOMETRY     = 255

metadata

再来看看元数据信息. 部分字段是存在元数据信息的, 比如varchar(N), 这个N就是它的元数据信息, 记录最大值. 具体信息等到 row event 再说. 基本上就是不固定长度的类型才有的.

null_bits

记录字段是否为空的. 和row_event里面的bitmask有关联的(到了再看). 每个字段使用1bit, 所以要使用 int((column_count+7)/8) 字节

opt

8.0 才有的opt optional metadata fields, 但8.0的mysqlbinlog不会解析这个信息(我怀疑是官方偷懒). 作为binlog解析工具, 我们还是要来解析的.

该opt是存在event结尾的, 所以null_bits后面全是opt, 不用记录大小, 直接读就行. 格式是tls的

1字节记录类型, L字节(pack_int)记录元数据长度. V就是记录长度的结果

先来看看1字节的字段类型: 1 表示第一个, 2表示第二个, 依次类推

不是所有类型都有, 有些要求 binlog_row_metadata=FULL 比如字段名字. 这里只看部分信息, 其它信息等row event的时候再看

类型

格式

描述

IGNEDNESS

对于有符号的字段, 每个字段使用1bit来表示.

符号

DEFAULT_CHARSET

字符集

COLUMN_CHARSET

字段字符集

COLUMN_NAME

1字节大小,后面就是字段名字

字段名字

SET_STR_VALUE

set的值

ENUM_STR_VALUE

enum的值

GEOMETRY_TYPE

空间坐标

SIMPLE_PRIMARY_KEY

主键

PRIMARY_KEY_WITH_PREFIX

主键前缀

ENUM_AND_SET_DEFAULT_CHARSET

ENUM_AND_SET_COLUMN_CHARSET

COLUMN_VISIBILITY

空间坐标

验证

现在我们来验证下

使用官方的mysqlbinlog解析信息如下:

就一丢丢, 只有名字....

再使用我们的工具来解析下

我们解析出来的信息就要多很多了. 比如字段名字啊, 符号啊之类的.再和数据库验证下吧

代码语言:sql
复制
(root@127.0.0.1) [ibd2sql]> desc ddcw_alltype_table;
+---------------+-------------------+------+-----+---------+----------------+
| Field         | Type              | Null | Key | Default | Extra          |
+---------------+-------------------+------+-----+---------+----------------+
| id            | int               | NO   | PRI | NULL    | auto_increment |
| int_col       | int               | YES  |     | NULL    |                |
| tinyint_col   | tinyint           | YES  |     | 1       |                |
| smallint_col  | smallint          | YES  |     | NULL    |                |
| mediumint_col | mediumint         | YES  |     | NULL    |                |
| bigint_col    | bigint            | YES  |     | NULL    |                |
| float_col     | float             | YES  |     | NULL    |                |
| double_col    | double            | YES  |     | NULL    |                |
| decimal_col   | decimal(10,2)     | YES  |     | NULL    |                |
| date_col      | date              | YES  |     | NULL    |                |
| datetime_col  | datetime          | YES  |     | NULL    |                |
| timestamp_col | timestamp         | YES  |     | NULL    |                |
| time_col      | time              | YES  |     | NULL    |                |
| year_col      | year              | YES  |     | NULL    |                |
| char_col      | char(100)         | YES  |     | NULL    |                |
| varchar_col   | varchar(200)      | YES  |     | aa      |                |
| binary_col    | binary(10)        | YES  |     | NULL    |                |
| varbinary_col | varbinary(20)     | YES  |     | NULL    |                |
| bit_col       | bit(4)            | YES  |     | NULL    |                |
| enum_col      | enum('A','B','C') | YES  |     | NULL    |                |
| set_col       | set('X','Y','Z')  | YES  |     | NULL    |                |
| josn_type     | json              | YES  |     | NULL    |                |
| newcol        | varchar(200)      | YES  |     | aa      |                |
| newcol2       | varchar(200)      | YES  |     | aa      |                |
| newcoldasdas2 | varchar(300)      | YES  |     | bbaa    |                |
+---------------+-------------------+------+-----+---------+----------------+

是对应上了的. 说明我们解析正确.

注: 由于数据存储只能按照字节存, 所以null_bits里面实际上可能结尾多几个bit. 可以看null_bit_bool 是按照字段数量来做的.

其它

有了元数据信息后, 我们就可以解析row event了. 然后就能拼接为SQL了. 但5.7版本没得opt信息, 无法区分符号, 也没得字段信息, 所以还是建议转为base64 方便点. (毕竟官方也是使用的base64来做的.)

话说pymysqlbinlog是用来干嘛的呢. 目前计划是实现如下功能. 数据过滤那一段已经实现了, 主要是比较简单...

代码语言:md
复制
注意: binlog的元数据信息可能不包含 字段名字, 字段符号(mysqlbinlog解析的时候也有这个问题, 所以要使用base64,或者知道元数据信息)

除了数据走stdout, 其它均走stderr
rollback  生成回滚SQL. 按照事务顺序 (读两次IO)
metadata  元数据信息的xml文件. 如果有的话, 则自动替换sql/sql2里面的字段名字
sql2      生成sql格式 (非注释), 由于数据类型转换可能存在问题, 建议使用base64格式
sql       生成sql格式 (注释的sql)
sql-complete 对于insert使用完整sql, 含字段名
sql-replace  使用replace替换insert和update
base64    生成base64格式(默认)
base64-disable 不要base64格式的数据,  如果没有sql/sql2, 则自动启动sql选项
debug     展示完整过程, 主要用于调试(stderr)
verbose   显示格外DEUG信息.

# 数据过滤, 优先匹配include, 匹配失败再匹配exclude, 匹配成功(返回False)则跳过
schema-include 同schema
schema-exclude
schema-replace 库名字替换, 所有符合要求的schema换为这个名字
table-include 同table
table-exclude
gtid-skip
gtid-include 同gtid
gtid-exclude
serverid-include
serverid-exclude
start-datetime
stop-datetime
start-position
stop-position

# 审计相关(不统计过滤掉的event), 走stderr
analyze-event 基于event做统计, 各event类型的数量, 大小
analyze-table 基于表做统计     各表的大小, 各表的dml操作数量/行数/大小
analyze-trx   基于事务做统计   大事务(不含gtid event, 但起止pos含gtid和xid).

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导读
  • TABLE_MAP_EVENT
    • pack_int
    • column_type
    • metadata
    • null_bits
    • opt
  • 验证
  • 其它
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档