@@ -18,6 +18,11 @@ package mysql
1818
1919import (
2020 "encoding/binary"
21+ "hash/crc32"
22+ )
23+
24+ const (
25+ FlagLogEventArtificial = 0x20
2126)
2227
2328// This file contains utility methods to create binlog replication
@@ -100,7 +105,12 @@ func (s *FakeBinlogStream) Packetize(f BinlogFormat, typ byte, flags uint16, dat
100105 }
101106
102107 result := make ([]byte , length )
103- binary .LittleEndian .PutUint32 (result [0 :4 ], s .Timestamp )
108+ switch typ {
109+ case eRotateEvent , eHeartbeatEvent :
110+ // timestamp remains zero
111+ default :
112+ binary .LittleEndian .PutUint32 (result [0 :4 ], s .Timestamp )
113+ }
104114 result [4 ] = typ
105115 binary .LittleEndian .PutUint32 (result [5 :9 ], s .ServerID )
106116 binary .LittleEndian .PutUint32 (result [9 :13 ], uint32 (length ))
@@ -109,6 +119,13 @@ func (s *FakeBinlogStream) Packetize(f BinlogFormat, typ byte, flags uint16, dat
109119 binary .LittleEndian .PutUint16 (result [17 :19 ], flags )
110120 }
111121 copy (result [f .HeaderLength :], data )
122+
123+ switch f .ChecksumAlgorithm {
124+ case BinlogChecksumAlgCRC32 :
125+ checksum := crc32 .ChecksumIEEE (result [0 : length - 4 ])
126+ binary .LittleEndian .PutUint32 (result [length - 4 :], checksum )
127+ }
128+
112129 return result
113130}
114131
@@ -157,12 +174,38 @@ func NewRotateEvent(f BinlogFormat, s *FakeBinlogStream, position uint64, filena
157174 len (filename )
158175 data := make ([]byte , length )
159176 binary .LittleEndian .PutUint64 (data [0 :8 ], position )
177+ copy (data [8 :], filename )
160178
161179 ev := s .Packetize (f , eRotateEvent , 0 , data )
162- ev [0 ] = 0
163- ev [1 ] = 0
164- ev [2 ] = 0
165- ev [3 ] = 0
180+ return NewMysql56BinlogEvent (ev )
181+ }
182+
183+ func NewFakeRotateEvent (f BinlogFormat , s * FakeBinlogStream , filename string ) BinlogEvent {
184+ length := 8 + // position
185+ len (filename )
186+ data := make ([]byte , length )
187+ binary .LittleEndian .PutUint64 (data [0 :8 ], 4 )
188+ copy (data [8 :], filename )
189+
190+ ev := s .Packetize (f , eRotateEvent , FlagLogEventArtificial , data )
191+ return NewMysql56BinlogEvent (ev )
192+ }
193+
194+ // NewHeartbeatEvent returns a HeartbeatEvent.
195+ // see https://dev.mysql.com/doc/internals/en/heartbeat-event.html
196+ func NewHeartbeatEvent (f BinlogFormat , s * FakeBinlogStream ) BinlogEvent {
197+ ev := s .Packetize (f , eHeartbeatEvent , 0 , []byte {})
198+ return NewMysql56BinlogEvent (ev )
199+ }
200+
201+ // NewHeartbeatEvent returns a HeartbeatEvent.
202+ // see https://dev.mysql.com/doc/internals/en/heartbeat-event.html
203+ func NewHeartbeatEventWithLogFile (f BinlogFormat , s * FakeBinlogStream , filename string ) BinlogEvent {
204+ length := len (filename )
205+ data := make ([]byte , length )
206+ copy (data , filename )
207+
208+ ev := s .Packetize (f , eHeartbeatEvent , 0 , data )
166209 return NewMysql56BinlogEvent (ev )
167210}
168211
@@ -172,7 +215,7 @@ func NewQueryEvent(f BinlogFormat, s *FakeBinlogStream, q Query) BinlogEvent {
172215 if q .Charset != nil {
173216 statusVarLength += 1 + 2 + 2 + 2
174217 }
175- length := 4 + // slave proxy id
218+ length := 4 + // proxy id
176219 4 + // execution time
177220 1 + // schema length
178221 2 + // error code
@@ -296,9 +339,9 @@ func NewTableMapEvent(f BinlogFormat, s *FakeBinlogStream, tableID uint64, tm *T
296339 1 + // table name length
297340 len (tm .Name ) +
298341 1 + // [00]
299- 1 + // column-count FIXME(alainjobart) len enc
342+ lenEncIntSize ( uint64 ( len ( tm . Types ))) + // column-count len enc
300343 len (tm .Types ) +
301- 1 + // lenenc-str column-meta-def FIXME(alainjobart) len enc
344+ lenEncIntSize ( uint64 ( metadataLength )) + // lenenc-str column-meta-def
302345 metadataLength +
303346 len (tm .CanBeNull .data )
304347 data := make ([]byte , length )
@@ -320,15 +363,10 @@ func NewTableMapEvent(f BinlogFormat, s *FakeBinlogStream, tableID uint64, tm *T
320363 data [pos ] = 0
321364 pos ++
322365
323- data [pos ] = byte (len (tm .Types )) // FIXME(alainjobart) lenenc
324- pos ++
325-
366+ pos = writeLenEncInt (data , pos , uint64 (len (tm .Types )))
326367 pos += copy (data [pos :], tm .Types )
327368
328- // Per-column meta data. Starting with len-enc length.
329- // FIXME(alainjobart) lenenc
330- data [pos ] = byte (metadataLength )
331- pos ++
369+ pos = writeLenEncInt (data , pos , uint64 (metadataLength ))
332370 for c , typ := range tm .Types {
333371 pos = metadataWrite (data , pos , typ , tm .Metadata [c ])
334372 }
@@ -366,10 +404,20 @@ func newRowsEvent(f BinlogFormat, s *FakeBinlogStream, typ byte, tableID uint64,
366404 panic ("Not implemented, post_header_length==6" )
367405 }
368406
407+ hasIdentify := typ == eUpdateRowsEventV1 || typ == eUpdateRowsEventV2 ||
408+ typ == eDeleteRowsEventV1 || typ == eDeleteRowsEventV2
409+ hasData := typ == eWriteRowsEventV1 || typ == eWriteRowsEventV2 ||
410+ typ == eUpdateRowsEventV1 || typ == eUpdateRowsEventV2
411+
412+ rowLen := rows .DataColumns .Count ()
413+ if hasIdentify {
414+ rowLen = rows .IdentifyColumns .Count ()
415+ }
416+
369417 length := 6 + // table id
370418 2 + // flags
371419 2 + // extra data length, no extra data.
372- 1 + // num columns FIXME(alainjobart) len enc
420+ lenEncIntSize ( uint64 ( rowLen )) + // num columns
373421 len (rows .IdentifyColumns .data ) + // only > 0 for Update & Delete
374422 len (rows .DataColumns .data ) // only > 0 for Write & Update
375423 for _ , row := range rows .Rows {
@@ -380,11 +428,6 @@ func newRowsEvent(f BinlogFormat, s *FakeBinlogStream, typ byte, tableID uint64,
380428 }
381429 data := make ([]byte , length )
382430
383- hasIdentify := typ == eUpdateRowsEventV1 || typ == eUpdateRowsEventV2 ||
384- typ == eDeleteRowsEventV1 || typ == eDeleteRowsEventV2
385- hasData := typ == eWriteRowsEventV1 || typ == eWriteRowsEventV2 ||
386- typ == eUpdateRowsEventV1 || typ == eUpdateRowsEventV2
387-
388431 data [0 ] = byte (tableID )
389432 data [1 ] = byte (tableID >> 8 )
390433 data [2 ] = byte (tableID >> 16 )
@@ -396,12 +439,7 @@ func newRowsEvent(f BinlogFormat, s *FakeBinlogStream, typ byte, tableID uint64,
396439 data [8 ] = 0x02
397440 data [9 ] = 0x00
398441
399- if hasIdentify {
400- data [10 ] = byte (rows .IdentifyColumns .Count ()) // FIXME(alainjobart) len
401- } else {
402- data [10 ] = byte (rows .DataColumns .Count ()) // FIXME(alainjobart) len
403- }
404- pos := 11
442+ pos := writeLenEncInt (data , 10 , uint64 (rowLen ))
405443
406444 if hasIdentify {
407445 pos += copy (data [pos :], rows .IdentifyColumns .data )
0 commit comments