More code documented
This commit is contained in:
parent
be37d25444
commit
db67e68078
@ -54,7 +54,7 @@ const (
|
|||||||
func (e *FormatDescriptionEvent) Decode(data []byte) error {
|
func (e *FormatDescriptionEvent) Decode(data []byte) error {
|
||||||
buf := tools.NewBuffer(data)
|
buf := tools.NewBuffer(data)
|
||||||
e.Version = buf.ReadUint16()
|
e.Version = buf.ReadUint16()
|
||||||
e.ServerVersion = trimString(buf.ReadStringVarLen(50))
|
e.ServerVersion = trimStringEOF(buf.ReadStringVarLen(50))
|
||||||
e.CreateTimestamp = buf.ReadUint32()
|
e.CreateTimestamp = buf.ReadUint32()
|
||||||
e.EventHeaderLength = buf.ReadUint8()
|
e.EventHeaderLength = buf.ReadUint8()
|
||||||
e.EventTypeHeaderLengths = buf.ReadStringEOF()
|
e.EventTypeHeaderLengths = buf.ReadStringEOF()
|
||||||
@ -64,9 +64,6 @@ func (e *FormatDescriptionEvent) Decode(data []byte) error {
|
|||||||
ChecksumAlgorithm: ChecksumAlgorithmUndefined,
|
ChecksumAlgorithm: ChecksumAlgorithmUndefined,
|
||||||
}
|
}
|
||||||
if e.ServerDetails.Version > 50601 {
|
if e.ServerDetails.Version > 50601 {
|
||||||
// Last 5 bytes are:
|
|
||||||
// [1] Checksum algorithm
|
|
||||||
// [4] Checksum
|
|
||||||
e.ServerDetails.ChecksumAlgorithm = ChecksumAlgorithm(data[len(data)-5])
|
e.ServerDetails.ChecksumAlgorithm = ChecksumAlgorithm(data[len(data)-5])
|
||||||
e.EventTypeHeaderLengths = e.EventTypeHeaderLengths[:len(e.EventTypeHeaderLengths)-5]
|
e.EventTypeHeaderLengths = e.EventTypeHeaderLengths[:len(e.EventTypeHeaderLengths)-5]
|
||||||
}
|
}
|
||||||
@ -127,7 +124,7 @@ func parseVersionNumber(v string) int {
|
|||||||
return major*10000 + minor*100 + patch
|
return major*10000 + minor*100 + patch
|
||||||
}
|
}
|
||||||
|
|
||||||
func trimString(str []byte) string {
|
func trimStringEOF(str []byte) string {
|
||||||
for i, c := range str {
|
for i, c := range str {
|
||||||
if c == 0x00 {
|
if c == 0x00 {
|
||||||
return string(str[:i])
|
return string(str[:i])
|
||||||
|
@ -2,7 +2,8 @@ package binlog
|
|||||||
|
|
||||||
import "github.com/localhots/bocadillo/tools"
|
import "github.com/localhots/bocadillo/tools"
|
||||||
|
|
||||||
// Position ...
|
// Position is a pair of log file name and a binary offset in it that is used to
|
||||||
|
// represent the beginning of the event description.
|
||||||
type Position struct {
|
type Position struct {
|
||||||
File string
|
File string
|
||||||
Offset uint64
|
Offset uint64
|
||||||
|
@ -28,12 +28,7 @@ type RowsFlag uint16
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// RowsFlagEndOfStatement is used to clear old table mappings.
|
// RowsFlagEndOfStatement is used to clear old table mappings.
|
||||||
RowsFlagEndOfStatement RowsFlag = 0x0001
|
RowsFlagEndOfStatement RowsFlag = 0x0001
|
||||||
rowsFlagNoForeignKeyChecks RowsFlag = 0x0002
|
|
||||||
rowsFlagNoUniqueKeyChecks RowsFlag = 0x0004
|
|
||||||
rowsFlagRowHasColumns RowsFlag = 0x0008
|
|
||||||
|
|
||||||
freeTableMapID = 0x00FFFFFF
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// PeekTableIDAndFlags returns table ID and flags without decoding whole event.
|
// PeekTableIDAndFlags returns table ID and flags without decoding whole event.
|
||||||
@ -229,7 +224,7 @@ func (e *RowsEvent) decodeValue(buf *tools.Buffer, ct mysql.ColumnType, meta uin
|
|||||||
case mysql.ColumnTypeLongblob:
|
case mysql.ColumnTypeLongblob:
|
||||||
return buf.ReadStringVarEnc(4)
|
return buf.ReadStringVarEnc(4)
|
||||||
|
|
||||||
// Bits
|
// Other
|
||||||
case mysql.ColumnTypeBit:
|
case mysql.ColumnTypeBit:
|
||||||
nbits := int(((meta >> 8) * 8) + (meta & 0xFF))
|
nbits := int(((meta >> 8) * 8) + (meta & 0xFF))
|
||||||
length = int(nbits+7) / 8
|
length = int(nbits+7) / 8
|
||||||
@ -241,8 +236,6 @@ func (e *RowsEvent) decodeValue(buf *tools.Buffer, ct mysql.ColumnType, meta uin
|
|||||||
v, n := mysql.DecodeBit(buf.Cur(), nbits, length)
|
v, n := mysql.DecodeBit(buf.Cur(), nbits, length)
|
||||||
buf.Skip(n)
|
buf.Skip(n)
|
||||||
return v
|
return v
|
||||||
|
|
||||||
// Stuff
|
|
||||||
case mysql.ColumnTypeEnum:
|
case mysql.ColumnTypeEnum:
|
||||||
return buf.ReadVarLen64(length)
|
return buf.ReadVarLen64(length)
|
||||||
|
|
||||||
|
@ -23,12 +23,12 @@ const (
|
|||||||
ColumnTypeTime ColumnType = 0x0b
|
ColumnTypeTime ColumnType = 0x0b
|
||||||
ColumnTypeDatetime ColumnType = 0x0c
|
ColumnTypeDatetime ColumnType = 0x0c
|
||||||
ColumnTypeYear ColumnType = 0x0d
|
ColumnTypeYear ColumnType = 0x0d
|
||||||
ColumnTypeNewDate ColumnType = 0x0e // Internal
|
ColumnTypeNewDate ColumnType = 0x0e
|
||||||
ColumnTypeVarchar ColumnType = 0x0f
|
ColumnTypeVarchar ColumnType = 0x0f
|
||||||
ColumnTypeBit ColumnType = 0x10
|
ColumnTypeBit ColumnType = 0x10
|
||||||
ColumnTypeTimestamp2 ColumnType = 0x11 // Internal
|
ColumnTypeTimestamp2 ColumnType = 0x11
|
||||||
ColumnTypeDatetime2 ColumnType = 0x12 // Internal
|
ColumnTypeDatetime2 ColumnType = 0x12
|
||||||
ColumnTypeTime2 ColumnType = 0x13 // Internal
|
ColumnTypeTime2 ColumnType = 0x13
|
||||||
|
|
||||||
ColumnTypeJSON ColumnType = 0xF5
|
ColumnTypeJSON ColumnType = 0xF5
|
||||||
ColumnTypeNewDecimal ColumnType = 0xF6
|
ColumnTypeNewDecimal ColumnType = 0xF6
|
||||||
|
206
mysql/time.go
206
mysql/time.go
@ -9,12 +9,14 @@ import (
|
|||||||
// Timezone is set for decoded datetime values.
|
// Timezone is set for decoded datetime values.
|
||||||
var Timezone = time.UTC
|
var Timezone = time.UTC
|
||||||
|
|
||||||
// DecodeYear ...
|
// DecodeYear decodes YEAR value.
|
||||||
|
// Spec: https://dev.mysql.com/doc/refman/8.0/en/year.html
|
||||||
func DecodeYear(v uint8) uint16 {
|
func DecodeYear(v uint8) uint16 {
|
||||||
return uint16(v) + 1900
|
return uint16(v) + 1900
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeDate ...
|
// DecodeDate decodes DATE value.
|
||||||
|
// Spec: https://dev.mysql.com/doc/refman/8.0/en/datetime.html
|
||||||
func DecodeDate(v uint32) string {
|
func DecodeDate(v uint32) string {
|
||||||
if v == 0 {
|
if v == 0 {
|
||||||
return "0000-00-00"
|
return "0000-00-00"
|
||||||
@ -22,7 +24,8 @@ func DecodeDate(v uint32) string {
|
|||||||
return fmt.Sprintf("%04d-%02d-%02d", v/(16*32), v/32%16, v%32)
|
return fmt.Sprintf("%04d-%02d-%02d", v/(16*32), v/32%16, v%32)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeTime ...
|
// DecodeTime decodes TIME value.
|
||||||
|
// Spec: https://dev.mysql.com/doc/refman/8.0/en/time.html
|
||||||
func DecodeTime(v uint32) string {
|
func DecodeTime(v uint32) string {
|
||||||
if v == 0 {
|
if v == 0 {
|
||||||
return "00:00:00"
|
return "00:00:00"
|
||||||
@ -34,97 +37,12 @@ func DecodeTime(v uint32) string {
|
|||||||
return fmt.Sprintf("%s%02d:%02d:%02d", sign, v/10000, (v%10000)/100, v%100)
|
return fmt.Sprintf("%s%02d:%02d:%02d", sign, v/10000, (v%10000)/100, v%100)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeTimestamp2 ...
|
// DecodeTime2 decodes TIME v2 value.
|
||||||
// Implementation borrowed from https://github.com/siddontang/go-mysql/
|
|
||||||
func DecodeTimestamp2(data []byte, dec uint16) (string, int) {
|
|
||||||
//get timestamp binary length
|
|
||||||
n := int(4 + (dec+1)/2)
|
|
||||||
sec := int64(binary.BigEndian.Uint32(data[0:4]))
|
|
||||||
usec := int64(0)
|
|
||||||
switch dec {
|
|
||||||
case 1, 2:
|
|
||||||
usec = int64(data[4]) * 10000
|
|
||||||
case 3, 4:
|
|
||||||
usec = int64(binary.BigEndian.Uint16(data[4:])) * 100
|
|
||||||
case 5, 6:
|
|
||||||
usec = int64(DecodeVarLen64BigEndian(data[4:7]))
|
|
||||||
}
|
|
||||||
|
|
||||||
if sec == 0 {
|
|
||||||
return formatZeroTime(int(usec), int(dec)), n
|
|
||||||
}
|
|
||||||
|
|
||||||
return FracTime{time.Unix(sec, usec*1000), int(dec)}.String(), n
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeDatetime ...
|
|
||||||
func DecodeDatetime(v uint64) string {
|
|
||||||
d := v / 1000000
|
|
||||||
t := v % 1000000
|
|
||||||
return FracTime{Time: time.Date(int(d/10000),
|
|
||||||
time.Month((d%10000)/100),
|
|
||||||
int(d%100),
|
|
||||||
int(t/10000),
|
|
||||||
int((t%10000)/100),
|
|
||||||
int(t%100),
|
|
||||||
0,
|
|
||||||
Timezone,
|
|
||||||
)}.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeDatetime2 ...
|
|
||||||
// Implementation borrowed from https://github.com/siddontang/go-mysql/
|
|
||||||
func DecodeDatetime2(data []byte, dec uint16) (string, int) {
|
|
||||||
const offset int64 = 0x8000000000
|
|
||||||
//get datetime binary length
|
|
||||||
n := int(5 + (dec+1)/2)
|
|
||||||
|
|
||||||
intPart := int64(DecodeVarLen64BigEndian(data[0:5])) - offset
|
|
||||||
var frac int64
|
|
||||||
|
|
||||||
switch dec {
|
|
||||||
case 1, 2:
|
|
||||||
frac = int64(data[5]) * 10000
|
|
||||||
case 3, 4:
|
|
||||||
frac = int64(binary.BigEndian.Uint16(data[5:7])) * 100
|
|
||||||
case 5, 6:
|
|
||||||
frac = int64(DecodeVarLen64BigEndian(data[5:8]))
|
|
||||||
}
|
|
||||||
|
|
||||||
if intPart == 0 {
|
|
||||||
return formatZeroTime(int(frac), int(dec)), n
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp := intPart<<24 + frac
|
|
||||||
//handle sign???
|
|
||||||
if tmp < 0 {
|
|
||||||
tmp = -tmp
|
|
||||||
}
|
|
||||||
|
|
||||||
// var secPart int64 = tmp % (1 << 24)
|
|
||||||
ymdhms := tmp >> 24
|
|
||||||
|
|
||||||
ymd := ymdhms >> 17
|
|
||||||
ym := ymd >> 5
|
|
||||||
hms := ymdhms % (1 << 17)
|
|
||||||
|
|
||||||
day := int(ymd % (1 << 5))
|
|
||||||
month := int(ym % 13)
|
|
||||||
year := int(ym / 13)
|
|
||||||
|
|
||||||
second := int(hms % (1 << 6))
|
|
||||||
minute := int((hms >> 6) % (1 << 6))
|
|
||||||
hour := int((hms >> 12))
|
|
||||||
|
|
||||||
return FracTime{time.Date(year, time.Month(month), day, hour, minute, second, int(frac*1000), Timezone), int(dec)}.String(), n
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeTime2 ...
|
|
||||||
// Implementation borrowed from https://github.com/siddontang/go-mysql/
|
// Implementation borrowed from https://github.com/siddontang/go-mysql/
|
||||||
func DecodeTime2(data []byte, dec uint16) (string, int) {
|
func DecodeTime2(data []byte, dec uint16) (string, int) {
|
||||||
const offset int64 = 0x800000000000
|
const offset int64 = 0x800000000000
|
||||||
const intOffset int64 = 0x800000
|
const intOffset int64 = 0x800000
|
||||||
//time binary length
|
// time binary length
|
||||||
n := int(3 + (dec+1)/2)
|
n := int(3 + (dec+1)/2)
|
||||||
|
|
||||||
tmp := int64(0)
|
tmp := int64(0)
|
||||||
@ -136,8 +54,8 @@ func DecodeTime2(data []byte, dec uint16) (string, int) {
|
|||||||
intPart = int64(DecodeVarLen64BigEndian(data[0:3])) - intOffset
|
intPart = int64(DecodeVarLen64BigEndian(data[0:3])) - intOffset
|
||||||
frac = int64(data[3])
|
frac = int64(data[3])
|
||||||
if intPart < 0 && frac > 0 {
|
if intPart < 0 && frac > 0 {
|
||||||
intPart++ /* Shift to the next integer value */
|
intPart++ // Shift to the next integer value
|
||||||
frac -= 0x100 /* -(0x100 - frac) */
|
frac -= 0x100 // -(0x100 - frac)
|
||||||
}
|
}
|
||||||
tmp = intPart<<24 + frac*10000
|
tmp = intPart<<24 + frac*10000
|
||||||
case 3:
|
case 3:
|
||||||
@ -145,12 +63,10 @@ func DecodeTime2(data []byte, dec uint16) (string, int) {
|
|||||||
intPart = int64(DecodeVarLen64BigEndian(data[0:3])) - intOffset
|
intPart = int64(DecodeVarLen64BigEndian(data[0:3])) - intOffset
|
||||||
frac = int64(binary.BigEndian.Uint16(data[3:5]))
|
frac = int64(binary.BigEndian.Uint16(data[3:5]))
|
||||||
if intPart < 0 && frac > 0 {
|
if intPart < 0 && frac > 0 {
|
||||||
/*
|
// Fix reverse fractional part order: "0x10000 - frac".
|
||||||
Fix reverse fractional part order: "0x10000 - frac".
|
// See comments for FSP=1 and FSP=2 above.
|
||||||
See comments for FSP=1 and FSP=2 above.
|
intPart++ // Shift to the next integer value
|
||||||
*/
|
frac -= 0x10000 // -(0x10000-frac)
|
||||||
intPart++ /* Shift to the next integer value */
|
|
||||||
frac -= 0x10000 /* -(0x10000-frac) */
|
|
||||||
}
|
}
|
||||||
tmp = intPart<<24 + frac*100
|
tmp = intPart<<24 + frac*100
|
||||||
|
|
||||||
@ -175,9 +91,9 @@ func DecodeTime2(data []byte, dec uint16) (string, int) {
|
|||||||
|
|
||||||
hms = tmp >> 24
|
hms = tmp >> 24
|
||||||
|
|
||||||
hour := (hms >> 12) % (1 << 10) /* 10 bits starting at 12th */
|
hour := (hms >> 12) % (1 << 10) // 10 bits starting at 12th
|
||||||
minute := (hms >> 6) % (1 << 6) /* 6 bits starting at 6th */
|
minute := (hms >> 6) % (1 << 6) // 6 bits starting at 6th
|
||||||
second := hms % (1 << 6) /* 6 bits starting at 0th */
|
second := hms % (1 << 6) // 6 bits starting at 0th
|
||||||
secPart := tmp % (1 << 24)
|
secPart := tmp % (1 << 24)
|
||||||
|
|
||||||
if secPart != 0 {
|
if secPart != 0 {
|
||||||
@ -187,6 +103,94 @@ func DecodeTime2(data []byte, dec uint16) (string, int) {
|
|||||||
return fmt.Sprintf("%s%02d:%02d:%02d", sign, hour, minute, second), n
|
return fmt.Sprintf("%s%02d:%02d:%02d", sign, hour, minute, second), n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DecodeTimestamp2 decodes TIMESTAMP v2 value.
|
||||||
|
// Spec: https://dev.mysql.com/doc/refman/8.0/en/datetime.html
|
||||||
|
// Implementation borrowed from https://github.com/siddontang/go-mysql/
|
||||||
|
func DecodeTimestamp2(data []byte, dec uint16) (string, int) {
|
||||||
|
// get timestamp binary length
|
||||||
|
n := int(4 + (dec+1)/2)
|
||||||
|
sec := int64(binary.BigEndian.Uint32(data[0:4]))
|
||||||
|
usec := int64(0)
|
||||||
|
switch dec {
|
||||||
|
case 1, 2:
|
||||||
|
usec = int64(data[4]) * 10000
|
||||||
|
case 3, 4:
|
||||||
|
usec = int64(binary.BigEndian.Uint16(data[4:])) * 100
|
||||||
|
case 5, 6:
|
||||||
|
usec = int64(DecodeVarLen64BigEndian(data[4:7]))
|
||||||
|
}
|
||||||
|
|
||||||
|
if sec == 0 {
|
||||||
|
return formatZeroTime(int(usec), int(dec)), n
|
||||||
|
}
|
||||||
|
|
||||||
|
return FracTime{time.Unix(sec, usec*1000), int(dec)}.String(), n
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeDatetime decodes DATETIME value.
|
||||||
|
// Spec: https://dev.mysql.com/doc/refman/8.0/en/datetime.html
|
||||||
|
func DecodeDatetime(v uint64) string {
|
||||||
|
d := v / 1000000
|
||||||
|
t := v % 1000000
|
||||||
|
return FracTime{Time: time.Date(int(d/10000),
|
||||||
|
time.Month((d%10000)/100),
|
||||||
|
int(d%100),
|
||||||
|
int(t/10000),
|
||||||
|
int((t%10000)/100),
|
||||||
|
int(t%100),
|
||||||
|
0,
|
||||||
|
Timezone,
|
||||||
|
)}.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeDatetime2 decodes DATETIME v2 value.
|
||||||
|
// Spec: https://dev.mysql.com/doc/refman/8.0/en/datetime.html
|
||||||
|
// Implementation borrowed from https://github.com/siddontang/go-mysql/
|
||||||
|
func DecodeDatetime2(data []byte, dec uint16) (string, int) {
|
||||||
|
const offset int64 = 0x8000000000
|
||||||
|
// get datetime binary length
|
||||||
|
n := int(5 + (dec+1)/2)
|
||||||
|
|
||||||
|
intPart := int64(DecodeVarLen64BigEndian(data[0:5])) - offset
|
||||||
|
var frac int64
|
||||||
|
|
||||||
|
switch dec {
|
||||||
|
case 1, 2:
|
||||||
|
frac = int64(data[5]) * 10000
|
||||||
|
case 3, 4:
|
||||||
|
frac = int64(binary.BigEndian.Uint16(data[5:7])) * 100
|
||||||
|
case 5, 6:
|
||||||
|
frac = int64(DecodeVarLen64BigEndian(data[5:8]))
|
||||||
|
}
|
||||||
|
|
||||||
|
if intPart == 0 {
|
||||||
|
return formatZeroTime(int(frac), int(dec)), n
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp := intPart<<24 + frac
|
||||||
|
// handle sign???
|
||||||
|
if tmp < 0 {
|
||||||
|
tmp = -tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
// var secPart int64 = tmp % (1 << 24)
|
||||||
|
ymdhms := tmp >> 24
|
||||||
|
|
||||||
|
ymd := ymdhms >> 17
|
||||||
|
ym := ymd >> 5
|
||||||
|
hms := ymdhms % (1 << 17)
|
||||||
|
|
||||||
|
day := int(ymd % (1 << 5))
|
||||||
|
month := int(ym % 13)
|
||||||
|
year := int(ym / 13)
|
||||||
|
|
||||||
|
second := int(hms % (1 << 6))
|
||||||
|
minute := int((hms >> 6) % (1 << 6))
|
||||||
|
hour := int((hms >> 12))
|
||||||
|
|
||||||
|
return FracTime{time.Date(year, time.Month(month), day, hour, minute, second, int(frac*1000), Timezone), int(dec)}.String(), n
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
fracTimeFormat = [...]string{
|
fracTimeFormat = [...]string{
|
||||||
"2006-01-02T15:04:05Z",
|
"2006-01-02T15:04:05Z",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user