Skip to content

Commit c61b8a9

Browse files
committed
Add some helper methods to TableMapEvent
1 parent 5dd4c32 commit c61b8a9

File tree

2 files changed

+102
-11
lines changed

2 files changed

+102
-11
lines changed

mysql/type.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package mysql
2+
3+
// IsNumericType returns true if the given type is numeric.
4+
func IsNumericType(typ byte) bool {
5+
switch typ {
6+
case MYSQL_TYPE_TINY,
7+
MYSQL_TYPE_SHORT,
8+
MYSQL_TYPE_INT24,
9+
MYSQL_TYPE_LONG,
10+
MYSQL_TYPE_LONGLONG,
11+
MYSQL_TYPE_FLOAT,
12+
MYSQL_TYPE_DOUBLE,
13+
MYSQL_TYPE_DECIMAL,
14+
MYSQL_TYPE_NEWDECIMAL:
15+
return true
16+
17+
default:
18+
return false
19+
}
20+
21+
}

replication/row_event.go

Lines changed: 81 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ type TableMapEvent struct {
3737
// The followings are available only after MySQL-8.0.1, see: `--binlog_row_metadata` and
3838
// https://mysqlhighavailability.com/more-metadata-is-written-into-binary-log/
3939

40-
OptionalMeta []byte
40+
optionalMeta []byte
4141

42-
SignednessBitmap []byte // len = (ColumnCount + 7) / 8
42+
SignednessBitmap []byte
4343
ColumnName [][]byte
4444
PrimaryKey []uint64 // A sequence of column indexes
4545
PrimaryKeyPrefix []uint64 // Prefix length 0 means that the whole column value is used
@@ -99,12 +99,12 @@ func (e *TableMapEvent) Decode(data []byte) error {
9999

100100
pos += nullBitmapSize
101101

102-
e.OptionalMeta = data[pos:]
103-
if len(e.OptionalMeta) == 0 {
102+
e.optionalMeta = data[pos:]
103+
if len(e.optionalMeta) == 0 {
104104
return nil
105105
}
106106

107-
if err = e.decodeOptionalMeta(e.OptionalMeta); err != nil {
107+
if err = e.decodeOptionalMeta(e.optionalMeta); err != nil {
108108
return err
109109
}
110110

@@ -259,6 +259,7 @@ func (e *TableMapEvent) decodeOptionalMeta(data []byte) error {
259259
}
260260

261261
default:
262+
// TODO: other meta
262263
}
263264

264265
}
@@ -275,17 +276,86 @@ func (e *TableMapEvent) Dump(w io.Writer) {
275276
fmt.Fprintf(w, "Column count: %d\n", e.ColumnCount)
276277
fmt.Fprintf(w, "Column type: \n%s", hex.Dump(e.ColumnType))
277278
fmt.Fprintf(w, "NULL bitmap: \n%s", hex.Dump(e.NullBitmap))
278-
fmt.Fprintf(w, "Optional meta: \n%s", hex.Dump(e.OptionalMeta))
279-
fmt.Fprintf(w, "Signedness bitmap\n%s", hex.Dump(e.SignednessBitmap))
280-
fmt.Fprintf(w, "Column name: \n")
281-
for _, name := range e.ColumnName {
282-
fmt.Fprintf(w, " %s\n", name)
283-
}
279+
fmt.Fprintf(w, "Optional meta: \n%s", hex.Dump(e.optionalMeta))
280+
fmt.Fprintf(w, "Signedness bitmap: \n%s", hex.Dump(e.SignednessBitmap))
284281
fmt.Fprintf(w, "Primary key: %v\n", e.PrimaryKey)
285282
fmt.Fprintf(w, "Primary key prefix: %v\n", e.PrimaryKeyPrefix)
283+
284+
colNameArr := e.ColumnNameArray()
285+
nullArr := e.NullableArray()
286+
unsignedArr := e.UnsignedArray()
287+
fmt.Fprintf(w, "Columns: \n")
288+
for i := 0; i < int(e.ColumnCount); i++ {
289+
if colNameArr != nil {
290+
fmt.Fprintf(w, " %s", colNameArr[i])
291+
} else {
292+
fmt.Fprintf(w, " <noname>")
293+
}
294+
295+
fmt.Fprintf(w, " type:%d", e.ColumnType[i])
296+
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")
304+
} else {
305+
fmt.Fprintf(w, " notnull")
306+
}
307+
}
308+
309+
fmt.Fprintf(w, "\n")
310+
}
286311
fmt.Fprintln(w)
287312
}
288313

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 {
317+
if 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
332+
}
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
338+
}
339+
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 {
343+
if len(e.SignednessBitmap) == 0 {
344+
return nil
345+
}
346+
p := 0
347+
ret := make([]bool, e.ColumnCount)
348+
for i := 0; i < len(ret); i++ {
349+
if !IsNumericType(e.ColumnType[i]) {
350+
ret[i] = false
351+
continue
352+
}
353+
ret[i] = e.SignednessBitmap[p/8]&(1<<(7-p%8)) != 0
354+
p++
355+
}
356+
return ret
357+
}
358+
289359
// RowsEventStmtEndFlag is set in the end of the statement.
290360
const RowsEventStmtEndFlag = 0x01
291361

0 commit comments

Comments
 (0)