116 lines
3.1 KiB
Go
116 lines
3.1 KiB
Go
package blt
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/localhots/pretty"
|
|
)
|
|
|
|
// FormatDescription is a description of binary log format.
|
|
type FormatDescription struct {
|
|
Version uint16
|
|
ServerVersion string
|
|
CreateTimestamp uint32
|
|
EventHeaderLength uint8
|
|
EventTypeHeaderLengths []uint8
|
|
ServerDetails ServerDetails
|
|
}
|
|
|
|
// ServerDetails contains server feature details.
|
|
type ServerDetails struct {
|
|
Flavor Flavor
|
|
Version int
|
|
ChecksumAlgorithm ChecksumAlgorithm
|
|
}
|
|
|
|
// Flavor defines the specific kind of MySQL-like database.
|
|
type Flavor string
|
|
|
|
// ChecksumAlgorithm is a checksum algorithm is the one used by the server.
|
|
type ChecksumAlgorithm byte
|
|
|
|
const (
|
|
// FlavorMySQL is the MySQL db flavor.
|
|
FlavorMySQL = "MySQL"
|
|
)
|
|
|
|
const (
|
|
// ChecksumAlgorithmNone means no checksum appened.
|
|
ChecksumAlgorithmNone ChecksumAlgorithm = 0x00
|
|
// ChecksumAlgorithmCRC32 used to append a 4 byte checksum at the end.
|
|
ChecksumAlgorithmCRC32 ChecksumAlgorithm = 0x01
|
|
// ChecksumAlgorithmUndefined is used when checksum algorithm is not known.
|
|
ChecksumAlgorithmUndefined ChecksumAlgorithm = 0xFF
|
|
)
|
|
|
|
// Spec: https://dev.mysql.com/doc/internals/en/format-description-event.html
|
|
func decodeFormatDescription(data []byte) FormatDescription {
|
|
buf := newReadBuffer(data)
|
|
fd := FormatDescription{
|
|
Version: buf.readUint16(),
|
|
ServerVersion: string(trimString(buf.readStringVarLen(50))),
|
|
CreateTimestamp: buf.readUint32(),
|
|
EventHeaderLength: buf.readUint8(),
|
|
EventTypeHeaderLengths: buf.readStringEOF(),
|
|
}
|
|
pretty.Println(fd)
|
|
fd.ServerDetails = ServerDetails{
|
|
Flavor: FlavorMySQL,
|
|
Version: parseVersionNumber(fd.ServerVersion),
|
|
ChecksumAlgorithm: ChecksumAlgorithmUndefined,
|
|
}
|
|
if fd.ServerDetails.Version > 50601 {
|
|
// Last 5 bytes are:
|
|
// [1] Checksum algorithm
|
|
// [4] Checksum
|
|
fd.ServerDetails.ChecksumAlgorithm = ChecksumAlgorithm(data[len(data)-5])
|
|
fd.EventTypeHeaderLengths = fd.EventTypeHeaderLengths[:len(fd.EventTypeHeaderLengths)-5]
|
|
}
|
|
|
|
return fd
|
|
}
|
|
|
|
func (fd FormatDescription) tableIDSize(et EventType) int {
|
|
if fd.headerLen(et) == 6 {
|
|
return 4
|
|
}
|
|
return 6
|
|
}
|
|
|
|
func (fd FormatDescription) headerLen(et EventType) int {
|
|
return int(fd.EventTypeHeaderLengths[et-1])
|
|
}
|
|
|
|
func (ca ChecksumAlgorithm) String() string {
|
|
switch ca {
|
|
case ChecksumAlgorithmNone:
|
|
return "None"
|
|
case ChecksumAlgorithmCRC32:
|
|
return "CRC32"
|
|
case ChecksumAlgorithmUndefined:
|
|
return "Undefined"
|
|
default:
|
|
return fmt.Sprintf("Unknown(%d)", ca)
|
|
}
|
|
}
|
|
|
|
// parseVersionNumber turns string version into a number just like the library
|
|
// mysql_get_server_version function does.
|
|
// Example: 5.7.19-log gets represented as 50719
|
|
// Spec: https://dev.mysql.com/doc/refman/8.0/en/mysql-get-server-version.html
|
|
func parseVersionNumber(v string) int {
|
|
tokens := strings.Split(v, ".")
|
|
major, _ := strconv.Atoi(tokens[0])
|
|
minor, _ := strconv.Atoi(tokens[1])
|
|
var patch int
|
|
for i, c := range tokens[2] {
|
|
if c < '0' || c > '9' {
|
|
patch, _ = strconv.Atoi(tokens[2][:i])
|
|
break
|
|
}
|
|
}
|
|
return major*10000 + minor*100 + patch
|
|
}
|