More code documented
This commit is contained in:
		
							parent
							
								
									be37d25444
								
							
						
					
					
						commit
						db67e68078
					
				@ -54,7 +54,7 @@ const (
 | 
			
		||||
func (e *FormatDescriptionEvent) Decode(data []byte) error {
 | 
			
		||||
	buf := tools.NewBuffer(data)
 | 
			
		||||
	e.Version = buf.ReadUint16()
 | 
			
		||||
	e.ServerVersion = trimString(buf.ReadStringVarLen(50))
 | 
			
		||||
	e.ServerVersion = trimStringEOF(buf.ReadStringVarLen(50))
 | 
			
		||||
	e.CreateTimestamp = buf.ReadUint32()
 | 
			
		||||
	e.EventHeaderLength = buf.ReadUint8()
 | 
			
		||||
	e.EventTypeHeaderLengths = buf.ReadStringEOF()
 | 
			
		||||
@ -64,9 +64,6 @@ func (e *FormatDescriptionEvent) Decode(data []byte) error {
 | 
			
		||||
		ChecksumAlgorithm: ChecksumAlgorithmUndefined,
 | 
			
		||||
	}
 | 
			
		||||
	if e.ServerDetails.Version > 50601 {
 | 
			
		||||
		// Last 5 bytes are:
 | 
			
		||||
		// [1] Checksum algorithm
 | 
			
		||||
		// [4] Checksum
 | 
			
		||||
		e.ServerDetails.ChecksumAlgorithm = ChecksumAlgorithm(data[len(data)-5])
 | 
			
		||||
		e.EventTypeHeaderLengths = e.EventTypeHeaderLengths[:len(e.EventTypeHeaderLengths)-5]
 | 
			
		||||
	}
 | 
			
		||||
@ -127,7 +124,7 @@ func parseVersionNumber(v string) int {
 | 
			
		||||
	return major*10000 + minor*100 + patch
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func trimString(str []byte) string {
 | 
			
		||||
func trimStringEOF(str []byte) string {
 | 
			
		||||
	for i, c := range str {
 | 
			
		||||
		if c == 0x00 {
 | 
			
		||||
			return string(str[:i])
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,8 @@ package binlog
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
	File   string
 | 
			
		||||
	Offset uint64
 | 
			
		||||
 | 
			
		||||
@ -28,12 +28,7 @@ type RowsFlag uint16
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// RowsFlagEndOfStatement is used to clear old table mappings.
 | 
			
		||||
	RowsFlagEndOfStatement     RowsFlag = 0x0001
 | 
			
		||||
	rowsFlagNoForeignKeyChecks RowsFlag = 0x0002
 | 
			
		||||
	rowsFlagNoUniqueKeyChecks  RowsFlag = 0x0004
 | 
			
		||||
	rowsFlagRowHasColumns      RowsFlag = 0x0008
 | 
			
		||||
 | 
			
		||||
	freeTableMapID = 0x00FFFFFF
 | 
			
		||||
	RowsFlagEndOfStatement RowsFlag = 0x0001
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 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:
 | 
			
		||||
		return buf.ReadStringVarEnc(4)
 | 
			
		||||
 | 
			
		||||
	// Bits
 | 
			
		||||
	// Other
 | 
			
		||||
	case mysql.ColumnTypeBit:
 | 
			
		||||
		nbits := int(((meta >> 8) * 8) + (meta & 0xFF))
 | 
			
		||||
		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)
 | 
			
		||||
		buf.Skip(n)
 | 
			
		||||
		return v
 | 
			
		||||
 | 
			
		||||
	// Stuff
 | 
			
		||||
	case mysql.ColumnTypeEnum:
 | 
			
		||||
		return buf.ReadVarLen64(length)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -23,12 +23,12 @@ const (
 | 
			
		||||
	ColumnTypeTime       ColumnType = 0x0b
 | 
			
		||||
	ColumnTypeDatetime   ColumnType = 0x0c
 | 
			
		||||
	ColumnTypeYear       ColumnType = 0x0d
 | 
			
		||||
	ColumnTypeNewDate    ColumnType = 0x0e // Internal
 | 
			
		||||
	ColumnTypeNewDate    ColumnType = 0x0e
 | 
			
		||||
	ColumnTypeVarchar    ColumnType = 0x0f
 | 
			
		||||
	ColumnTypeBit        ColumnType = 0x10
 | 
			
		||||
	ColumnTypeTimestamp2 ColumnType = 0x11 // Internal
 | 
			
		||||
	ColumnTypeDatetime2  ColumnType = 0x12 // Internal
 | 
			
		||||
	ColumnTypeTime2      ColumnType = 0x13 // Internal
 | 
			
		||||
	ColumnTypeTimestamp2 ColumnType = 0x11
 | 
			
		||||
	ColumnTypeDatetime2  ColumnType = 0x12
 | 
			
		||||
	ColumnTypeTime2      ColumnType = 0x13
 | 
			
		||||
 | 
			
		||||
	ColumnTypeJSON       ColumnType = 0xF5
 | 
			
		||||
	ColumnTypeNewDecimal ColumnType = 0xF6
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										206
									
								
								mysql/time.go
									
									
									
									
									
								
							
							
						
						
									
										206
									
								
								mysql/time.go
									
									
									
									
									
								
							@ -9,12 +9,14 @@ import (
 | 
			
		||||
// Timezone is set for decoded datetime values.
 | 
			
		||||
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 {
 | 
			
		||||
	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 {
 | 
			
		||||
	if v == 0 {
 | 
			
		||||
		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)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DecodeTime ...
 | 
			
		||||
// DecodeTime decodes TIME value.
 | 
			
		||||
// Spec: https://dev.mysql.com/doc/refman/8.0/en/time.html
 | 
			
		||||
func DecodeTime(v uint32) string {
 | 
			
		||||
	if v == 0 {
 | 
			
		||||
		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)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DecodeTimestamp2 ...
 | 
			
		||||
// 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 ...
 | 
			
		||||
// DecodeTime2 decodes TIME v2 value.
 | 
			
		||||
// Implementation borrowed from https://github.com/siddontang/go-mysql/
 | 
			
		||||
func DecodeTime2(data []byte, dec uint16) (string, int) {
 | 
			
		||||
	const offset int64 = 0x800000000000
 | 
			
		||||
	const intOffset int64 = 0x800000
 | 
			
		||||
	//time  binary length
 | 
			
		||||
	// time  binary length
 | 
			
		||||
	n := int(3 + (dec+1)/2)
 | 
			
		||||
 | 
			
		||||
	tmp := int64(0)
 | 
			
		||||
@ -136,8 +54,8 @@ func DecodeTime2(data []byte, dec uint16) (string, int) {
 | 
			
		||||
		intPart = int64(DecodeVarLen64BigEndian(data[0:3])) - intOffset
 | 
			
		||||
		frac = int64(data[3])
 | 
			
		||||
		if intPart < 0 && frac > 0 {
 | 
			
		||||
			intPart++     /* Shift to the next integer value */
 | 
			
		||||
			frac -= 0x100 /* -(0x100 - frac) */
 | 
			
		||||
			intPart++     // Shift to the next integer value
 | 
			
		||||
			frac -= 0x100 // -(0x100 - frac)
 | 
			
		||||
		}
 | 
			
		||||
		tmp = intPart<<24 + frac*10000
 | 
			
		||||
	case 3:
 | 
			
		||||
@ -145,12 +63,10 @@ func DecodeTime2(data []byte, dec uint16) (string, int) {
 | 
			
		||||
		intPart = int64(DecodeVarLen64BigEndian(data[0:3])) - intOffset
 | 
			
		||||
		frac = int64(binary.BigEndian.Uint16(data[3:5]))
 | 
			
		||||
		if intPart < 0 && frac > 0 {
 | 
			
		||||
			/*
 | 
			
		||||
			   Fix reverse fractional part order: "0x10000 - frac".
 | 
			
		||||
			   See comments for FSP=1 and FSP=2 above.
 | 
			
		||||
			*/
 | 
			
		||||
			intPart++       /* Shift to the next integer value */
 | 
			
		||||
			frac -= 0x10000 /* -(0x10000-frac) */
 | 
			
		||||
			// Fix reverse fractional part order: "0x10000 - frac".
 | 
			
		||||
			// See comments for FSP=1 and FSP=2 above.
 | 
			
		||||
			intPart++       // Shift to the next integer value
 | 
			
		||||
			frac -= 0x10000 // -(0x10000-frac)
 | 
			
		||||
		}
 | 
			
		||||
		tmp = intPart<<24 + frac*100
 | 
			
		||||
 | 
			
		||||
@ -175,9 +91,9 @@ func DecodeTime2(data []byte, dec uint16) (string, int) {
 | 
			
		||||
 | 
			
		||||
	hms = tmp >> 24
 | 
			
		||||
 | 
			
		||||
	hour := (hms >> 12) % (1 << 10) /* 10 bits starting at 12th */
 | 
			
		||||
	minute := (hms >> 6) % (1 << 6) /* 6 bits starting at 6th   */
 | 
			
		||||
	second := hms % (1 << 6)        /* 6 bits starting at 0th   */
 | 
			
		||||
	hour := (hms >> 12) % (1 << 10) // 10 bits starting at 12th
 | 
			
		||||
	minute := (hms >> 6) % (1 << 6) // 6 bits starting at 6th
 | 
			
		||||
	second := hms % (1 << 6)        // 6 bits starting at 0th
 | 
			
		||||
	secPart := tmp % (1 << 24)
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 (
 | 
			
		||||
	fracTimeFormat = [...]string{
 | 
			
		||||
		"2006-01-02T15:04:05Z",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user