@@ -32,14 +32,14 @@ type TableMapEvent struct {
3232ColumnType []byte
3333ColumnMeta []uint16
3434
35- NullBitmap []byte // len = (ColumnCount + 7) / 8
35+ //len = (ColumnCount + 7) / 8
36+ NullBitmap []byte
3637
3738// The followings are available only after MySQL-8.0.1, see: `--binlog_row_metadata` and
3839// https://mysqlhighavailability.com/more-metadata-is-written-into-binary-log/
3940
40- optionalMeta []byte
41-
4241SignednessBitmap []byte
42+
4343ColumnName [][]byte
4444PrimaryKey []uint64 // A sequence of column indexes
4545PrimaryKeyPrefix []uint64 // Prefix length 0 means that the whole column value is used
@@ -99,12 +99,12 @@ func (e *TableMapEvent) Decode(data []byte) error {
9999
100100pos += nullBitmapSize
101101
102- e . optionalMeta = data [pos :]
103- if len (e . optionalMeta ) == 0 {
102+ optionalMeta : = data [pos :]
103+ if len (optionalMeta ) == 0 {
104104return nil
105105}
106106
107- if err = e .decodeOptionalMeta (e . optionalMeta ); err != nil {
107+ if err = e .decodeOptionalMeta (optionalMeta ); err != nil {
108108return err
109109}
110110
@@ -276,78 +276,88 @@ func (e *TableMapEvent) Dump(w io.Writer) {
276276fmt .Fprintf (w , "Column count: %d\n " , e .ColumnCount )
277277fmt .Fprintf (w , "Column type: \n %s" , hex .Dump (e .ColumnType ))
278278fmt .Fprintf (w , "NULL bitmap: \n %s" , hex .Dump (e .NullBitmap ))
279- fmt . Fprintf ( w , "Optional meta: \n %s" , hex . Dump ( e . optionalMeta ))
279+
280280fmt .Fprintf (w , "Signedness bitmap: \n %s" , hex .Dump (e .SignednessBitmap ))
281281fmt .Fprintf (w , "Primary key: %v\n " , e .PrimaryKey )
282282fmt .Fprintf (w , "Primary key prefix: %v\n " , e .PrimaryKeyPrefix )
283283
284- colNameArr := e .ColumnNameArray ()
285- nullArr := e .NullableArray ()
286- unsignedArr := e .UnsignedArray ()
284+ unsignedMap := e .UnsignedMap ()
285+
286+ nameMaxLen := 0
287+ for _ , name := range e .ColumnName {
288+ if len (name ) > nameMaxLen {
289+ nameMaxLen = len (name )
290+ }
291+ }
292+ nameFmt := " %s"
293+ if nameMaxLen > 0 {
294+ nameFmt = fmt .Sprintf (" %%-%ds" , nameMaxLen )
295+ }
296+
297+ primaryKey := map [int ]struct {}{}
298+ for _ , pk := range e .PrimaryKey {
299+ primaryKey [int (pk )] = struct {}{}
300+ }
301+
287302fmt .Fprintf (w , "Columns: \n " )
288303for i := 0 ; i < int (e .ColumnCount ); i ++ {
289- if colNameArr != nil {
290- fmt .Fprintf (w , " %s" , colNameArr [ i ] )
304+ if len ( e . ColumnName ) == 0 {
305+ fmt .Fprintf (w , nameFmt , "<n/a>" )
291306} else {
292- fmt .Fprintf (w , " <noname>" )
307+ fmt .Fprintf (w , nameFmt , e . ColumnName [ i ] )
293308}
294309
295- fmt .Fprintf (w , " type:%d " , e .ColumnType [i ])
310+ fmt .Fprintf (w , " type=%-3d " , e .ColumnType [i ])
296311
297- if unsignedArr != nil && unsignedArr [i ] {
298- fmt .Fprintf (w , " unsigned" )
299- }
300-
301- if nullArr != nil {
302- if nullArr [i ] {
303- fmt .Fprintf (w , " null" )
312+ if IsNumericType (e .ColumnType [i ]) {
313+ if unsignedMap == nil {
314+ fmt .Fprintf (w , " unsigned=<n/a>" )
315+ } else if unsignedMap [i ] {
316+ fmt .Fprintf (w , " unsigned=yes" )
304317} else {
305- fmt .Fprintf (w , " notnull " )
318+ fmt .Fprintf (w , " unsigned=no " )
306319}
307320}
308321
322+ available , nullable := e .Nullable (i )
323+ if ! available {
324+ fmt .Fprintf (w , " null=<n/a>" )
325+ } else if nullable {
326+ fmt .Fprintf (w , " null=yes" )
327+ } else {
328+ fmt .Fprintf (w , " null=no " )
329+ }
330+
331+ if _ , ok := primaryKey [i ]; ok {
332+ fmt .Fprintf (w , " pri" )
333+ }
334+
309335fmt .Fprintf (w , "\n " )
310336}
311337fmt .Fprintln (w )
312338}
313339
314- // NullableArray returns an array of nullablity for each column: true if the column is nullable.
315- // It returns nil if not available.
316- func (e * TableMapEvent ) NullableArray () []bool {
340+ // Nullable returns the nullablity of the i-th column.
341+ // If null bits are not available, available is false.
342+ // i must be in range [0, ColumnCount).
343+ func (e * TableMapEvent ) Nullable (i int ) (available , nullable bool ) {
317344if len (e .NullBitmap ) == 0 {
318- return nil
319- }
320- ret := make ([]bool , e .ColumnCount )
321- for i := 0 ; i < len (ret ); i ++ {
322- ret [i ] = e .NullBitmap [i / 8 ]& (1 << (i % 8 )) != 0
323- }
324- return ret
325- }
326-
327- // ColumnNameArray returns an array of column names.
328- // It returns nil if not available.
329- func (e * TableMapEvent ) ColumnNameArray () []string {
330- if len (e .ColumnName ) == 0 {
331- return nil
345+ return
332346}
333- ret := make ([]string , e .ColumnCount )
334- for i := 0 ; i < len (ret ); i ++ {
335- ret [i ] = string (e .ColumnName [i ])
336- }
337- return ret
347+ return true , e .NullBitmap [i / 8 ]& (1 << (i % 8 )) != 0
338348}
339349
340- // UnsignedArray returns an array of signedness for each column: true if the column is numeric and it's unsigned.
341- // It returns nil if not available.
342- func (e * TableMapEvent ) UnsignedArray () []bool {
350+ // UnsignedMap returns a map: column index -> unsigned.
351+ // Note that only numeric columns will be returned.
352+ // If signedness bits are not available, nil is returned.
353+ func (e * TableMapEvent ) UnsignedMap () map [int ]bool {
343354if len (e .SignednessBitmap ) == 0 {
344355return nil
345356}
346357p := 0
347- ret := make ([ ]bool , e . ColumnCount )
348- for i := 0 ; i < len ( ret ); i ++ {
358+ ret := make (map [ int ]bool )
359+ for i := 0 ; i < int ( e . ColumnCount ); i ++ {
349360if ! IsNumericType (e .ColumnType [i ]) {
350- ret [i ] = false
351361continue
352362}
353363ret [i ] = e .SignednessBitmap [p / 8 ]& (1 << (7 - p % 8 )) != 0
0 commit comments