1
0
Fork 0

Move parser code to it's own package

This commit is contained in:
Gregory Eremin 2018-11-05 18:15:59 +01:00
parent 93f9ee8b52
commit 3a5271bca3
13 changed files with 182 additions and 80 deletions

View File

@ -7,7 +7,7 @@ import (
"os" "os"
"time" "time"
"github.com/localhots/blt" "github.com/localhots/blt/parser"
"github.com/localhots/gobelt/log" "github.com/localhots/gobelt/log"
) )
@ -22,13 +22,13 @@ func main() {
validate((*dsn != ""), "Database source name is not set") validate((*dsn != ""), "Database source name is not set")
validate((*id != 0), "Server ID is not set") validate((*id != 0), "Server ID is not set")
validate((*file != ""), "Binary log file is not set") validate((*file != ""), "Binary log file is not set")
conf := blt.Config{ conf := parser.Config{
ServerID: uint32(*id), ServerID: uint32(*id),
File: *file, File: *file,
Offset: uint32(*offset), Offset: uint32(*offset),
} }
reader, err := blt.Connect(*dsn, conf) reader, err := parser.Connect(*dsn, conf)
if err != nil { if err != nil {
log.Fatalf(ctx, "Failed to establish connection: %v", err) log.Fatalf(ctx, "Failed to establish connection: %v", err)
} }

View File

@ -1,64 +0,0 @@
package blt
import (
"fmt"
"github.com/localhots/pretty"
)
// Rows contains a Rows Event.
type Rows struct {
EventType EventType
TableID uint64
Flags uint16
ExtraData []byte
ColumnCount uint64
ColumnBitmap1 []byte
ColumnBitmap2 []byte
Rows [][]interface{}
}
type rowsFlag uint16
const (
rowsFlagEndOfStatement rowsFlag = 0x0001
rowsFlagNoForeignKeyChecks rowsFlag = 0x0002
rowsFlagNoUniqueKeyChecks rowsFlag = 0x0004
rowsFlagRowHasColumns rowsFlag = 0x0008
freeTableMapID = 0x00FFFFFF
)
func (r *Reader) decodeRowsEvent(data []byte, typ EventType) {
// pretty.Println(data)
buf := newReadBuffer(data)
rows := Rows{EventType: typ}
idSize := r.format.tableIDSize(typ)
if idSize == 6 {
rows.TableID = buf.readUint48()
} else {
rows.TableID = uint64(buf.readUint32())
}
rows.Flags = buf.readUint16()
if typ.isEither(WriteRowsEventV2, UpdateRowsEventV2, DeleteRowsEventV2) {
// Extra data length is part of extra data, deduct 2 bytes as they
// already store its length
extraLen := buf.readUint16() - 2
rows.ExtraData = buf.readStringVarLen(int(extraLen))
}
rows.ColumnCount, _ = buf.readUintLenEnc()
rows.ColumnBitmap1 = buf.readStringVarLen(int(rows.ColumnCount+7) / 8)
if typ.isEither(UpdateRowsEventV2, UpdateRowsEventV1) {
rows.ColumnBitmap2 = buf.readStringVarLen(int(rows.ColumnCount+7) / 8)
}
tm, ok := r.tableMap[rows.TableID]
if !ok {
panic(fmt.Errorf("Out of sync: no table map definition for ID=%d", rows.TableID))
}
pretty.Println(typ.String(), rows, tm, buf.cur())
}

View File

@ -1,4 +1,4 @@
package blt package parser
import ( import (
"encoding/binary" "encoding/binary"

View File

@ -1,4 +1,4 @@
package blt package parser
import ( import (
"fmt" "fmt"

View File

@ -1,4 +1,4 @@
package blt package parser
import ( import (
"encoding/binary" "encoding/binary"

View File

@ -1,4 +1,4 @@
package blt package parser
import "testing" import "testing"

View File

@ -1,11 +1,9 @@
package blt package parser
import ( import (
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
"github.com/localhots/pretty"
) )
// FormatDescription is a description of binary log format. // FormatDescription is a description of binary log format.
@ -55,7 +53,6 @@ func decodeFormatDescription(data []byte) FormatDescription {
EventHeaderLength: buf.readUint8(), EventHeaderLength: buf.readUint8(),
EventTypeHeaderLengths: buf.readStringEOF(), EventTypeHeaderLengths: buf.readStringEOF(),
} }
pretty.Println(fd)
fd.ServerDetails = ServerDetails{ fd.ServerDetails = ServerDetails{
Flavor: FlavorMySQL, Flavor: FlavorMySQL,
Version: parseVersionNumber(fd.ServerVersion), Version: parseVersionNumber(fd.ServerVersion),

View File

@ -1,4 +1,4 @@
package blt package parser
import ( import (
"errors" "errors"

View File

@ -1,4 +1,4 @@
package blt package parser
func (r *Reader) decodeRotateEvent(data []byte) Position { func (r *Reader) decodeRotateEvent(data []byte) Position {
buf := newReadBuffer(data) buf := newReadBuffer(data)

169
parser/event_rows.go Normal file
View File

@ -0,0 +1,169 @@
package parser
import (
"fmt"
"github.com/localhots/pretty"
)
// Rows contains a Rows Event.
type Rows struct {
EventType EventType
TableID uint64
Flags uint16
ExtraData []byte
ColumnCount uint64
ColumnBitmap1 []byte
ColumnBitmap2 []byte
Rows [][]interface{}
TableMap *TableMap
}
type rowsFlag uint16
const (
rowsFlagEndOfStatement rowsFlag = 0x0001
rowsFlagNoForeignKeyChecks rowsFlag = 0x0002
rowsFlagNoUniqueKeyChecks rowsFlag = 0x0004
rowsFlagRowHasColumns rowsFlag = 0x0008
freeTableMapID = 0x00FFFFFF
)
func (r *Reader) decodeRowsEvent(data []byte, typ EventType) {
// pretty.Println(data)
buf := newReadBuffer(data)
rows := Rows{EventType: typ}
idSize := r.format.tableIDSize(typ)
if idSize == 6 {
rows.TableID = buf.readUint48()
} else {
rows.TableID = uint64(buf.readUint32())
}
rows.Flags = buf.readUint16()
if typ.isEither(WriteRowsEventV2, UpdateRowsEventV2, DeleteRowsEventV2) {
// Extra data length is part of extra data, deduct 2 bytes as they
// already store its length
extraLen := buf.readUint16() - 2
rows.ExtraData = buf.readStringVarLen(int(extraLen))
}
rows.ColumnCount, _ = buf.readUintLenEnc()
rows.ColumnBitmap1 = buf.readStringVarLen(int(rows.ColumnCount+7) / 8)
if typ.isEither(UpdateRowsEventV2, UpdateRowsEventV1) {
rows.ColumnBitmap2 = buf.readStringVarLen(int(rows.ColumnCount+7) / 8)
}
tm, ok := r.tableMap[rows.TableID]
if !ok {
panic(fmt.Errorf("Out of sync: no table map definition for ID=%d", rows.TableID))
}
rows.TableMap = &tm
pretty.Println(typ.String(), rows, tm, buf.cur())
rows.decodeRows(buf, rows.ColumnBitmap1)
}
func (r *Rows) decodeRows(buf *buffer, bm []byte) {
count := 0
for i := 0; i < int(r.ColumnCount); i++ {
if isBitSet(bm, i) {
count++
}
}
count = (count + 7) / 8
nullBM := buf.readStringVarLen(count)
nullCnt := 0
row := make([]interface{}, r.ColumnCount)
pretty.Println(count, nullBM)
var err error
for i := 0; i < int(r.ColumnCount); i++ {
if !isBitSet(bm, i) {
continue
}
isNull := (uint32(nullBM[nullCnt/8]) >> uint32(nullCnt%8)) & 0x01
nullCnt++
if isNull > 0 {
row[i] = nil
continue
}
row[i], err = r.decodeValue(buf, columnType(r.TableMap.ColumnTypes[i]), r.TableMap.ColumnMeta[i])
if err != nil {
panic(err)
}
}
}
func (r *Rows) decodeValue(buf *buffer, ct columnType, meta uint16) (interface{}, error) {
switch ct {
case colTypeDecimal:
pretty.Println("Type", ct.String())
case colTypeTiny:
pretty.Println("Type", ct.String())
case colTypeShort:
pretty.Println("Type", ct.String())
case colTypeLong:
pretty.Println("Type", ct.String())
case colTypeFloat:
pretty.Println("Type", ct.String())
case colTypeDouble:
pretty.Println("Type", ct.String())
case colTypeNull:
pretty.Println("Type", ct.String())
case colTypeTimestamp:
pretty.Println("Type", ct.String())
case colTypeLonglong:
pretty.Println("Type", ct.String())
case colTypeInt24:
pretty.Println("Type", ct.String())
case colTypeDate:
pretty.Println("Type", ct.String())
case colTypeTime:
pretty.Println("Type", ct.String())
case colTypeDatetime:
pretty.Println("Type", ct.String())
case colTypeYear:
pretty.Println("Type", ct.String())
case colTypeVarchar:
pretty.Println("Type", ct.String())
case colTypeBit:
pretty.Println("Type", ct.String())
case colTypeJSON:
pretty.Println("Type", ct.String())
case colTypeNewDecimal:
pretty.Println("Type", ct.String())
case colTypeEnum:
pretty.Println("Type", ct.String())
case colTypeSet:
pretty.Println("Type", ct.String())
case colTypeTinyblob:
pretty.Println("Type", ct.String())
case colTypeMediumblob:
pretty.Println("Type", ct.String())
case colTypeLongblob:
pretty.Println("Type", ct.String())
case colTypeBlob:
pretty.Println("Type", ct.String())
case colTypeVarstring:
pretty.Println("Type", ct.String())
case colTypeString:
pretty.Println("Type", ct.String())
case colTypeGeometry:
pretty.Println("Type", ct.String())
}
return nil, nil
}
func isBitSet(bm []byte, i int) bool {
return bm[i>>3]&(1<<(uint(i)&7)) > 0
}

View File

@ -1,4 +1,4 @@
package blt package parser
// TableMap ... // TableMap ...
type TableMap struct { type TableMap struct {

View File

@ -1,4 +1,4 @@
package blt package parser
import ( import (
"fmt" "fmt"

View File

@ -1,4 +1,4 @@
package blt package parser
import ( import (
"context" "context"