Skip to content

Commit 8b9c05e

Browse files
Ryan-Gitsiddontang
authored andcommitted
fix(canal): fix mysql unsigned medium int (#399)
* fix(canal): fix mysql unsigned medium int
1 parent dbe0224 commit 8b9c05e

File tree

5 files changed

+28
-5
lines changed

5 files changed

+28
-5
lines changed

canal/canal_test.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,16 @@ func (s *canalTestSuite) SetUpSuite(c *C) {
5353
id int AUTO_INCREMENT,
5454
content blob DEFAULT NULL,
5555
name varchar(100),
56+
mi mediumint(8) NOT NULL DEFAULT 0,
57+
umi mediumint(8) unsigned NOT NULL DEFAULT 0,
5658
PRIMARY KEY(id)
5759
)ENGINE=innodb;
5860
`
5961

6062
s.execute(c, sql)
6163

6264
s.execute(c, "DELETE FROM test.canal_test")
63-
s.execute(c, "INSERT INTO test.canal_test (content, name) VALUES (?, ?), (?, ?), (?, ?)", "1", "a", `\0\ndsfasdf`, "b", "", "c")
65+
s.execute(c, "INSERT INTO test.canal_test (content, name, mi, umi) VALUES (?, ?, ?, ?), (?, ?, ?, ?), (?, ?, ?, ?)", "1", "a", 0, 0, `\0\ndsfasdf`, "b", 1, 16777215, "", "c", -1, 1)
6466

6567
s.execute(c, "SET GLOBAL binlog_format = 'ROW'")
6668

@@ -96,6 +98,10 @@ type testEventHandler struct {
9698

9799
func (h *testEventHandler) OnRow(e *RowsEvent) error {
98100
log.Infof("OnRow %s %v\n", e.Action, e.Rows)
101+
umi, ok := e.Rows[0][4].(uint32) // 4th col is umi. mysqldump gives uint64 instead of uint32
102+
if ok && (umi != 0 && umi != 1 && umi != 16777215) {
103+
return fmt.Errorf("invalid unsigned medium int %d", umi)
104+
}
99105
return nil
100106
}
101107

@@ -113,6 +119,7 @@ func (s *canalTestSuite) TestCanal(c *C) {
113119
for i := 1; i < 10; i++ {
114120
s.execute(c, "INSERT INTO test.canal_test (name) VALUES (?)", fmt.Sprintf("%d", i))
115121
}
122+
s.execute(c, "INSERT INTO test.canal_test (mi,umi) VALUES (?,?), (?,?), (?,?)", 0, 0, -1, 16777215, 1, 1)
116123
s.execute(c, "ALTER TABLE test.canal_test ADD `age` INT(5) NOT NULL AFTER `name`")
117124
s.execute(c, "INSERT INTO test.canal_test (name,age) VALUES (?,?)", "d", "18")
118125

canal/dump.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func (h *dumpParseHandler) Data(db string, table string, values []string) error
5252
} else if v == "_binary ''" {
5353
vs[i] = []byte{}
5454
} else if v[0] != '\'' {
55-
if tableInfo.Columns[i].Type == schema.TYPE_NUMBER {
55+
if tableInfo.Columns[i].Type == schema.TYPE_NUMBER || tableInfo.Columns[i].Type == schema.TYPE_MEDIUM_INT {
5656
n, err := strconv.ParseInt(v, 10, 64)
5757
if err != nil {
5858
return fmt.Errorf("parse row %v at %d error %v, int expected", values, i, err)

canal/rows.go

+14-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package canal
22

33
import (
44
"fmt"
5-
65
"github.com/siddontang/go-mysql/replication"
76
"github.com/siddontang/go-mysql/schema"
87
)
@@ -41,6 +40,8 @@ func newRowsEvent(table *schema.Table, action string, rows [][]interface{}, head
4140
return e
4241
}
4342

43+
const maxMediumintUnsigned int32 = 16777215
44+
4445
func (r *RowsEvent) handleUnsigned() {
4546
// Handle Unsigned Columns here, for binlog replication, we can't know the integer is unsigned or not,
4647
// so we use int type but this may cause overflow outside sometimes, so we must convert to the really .
@@ -57,7 +58,18 @@ func (r *RowsEvent) handleUnsigned() {
5758
case int16:
5859
r.Rows[i][index] = uint16(t)
5960
case int32:
60-
r.Rows[i][index] = uint32(t)
61+
if r.Table.Columns[i].Type == schema.TYPE_MEDIUM_INT {
62+
// problem with mediumint is that it's a 3-byte type. There is no compatible golang type to match that.
63+
// So to convert from negative to positive we'd need to convert the value manually
64+
if i >= 0 {
65+
r.Rows[i][index] = uint32(t)
66+
} else {
67+
r.Rows[i][index] = uint32(maxMediumintUnsigned + t + 1)
68+
}
69+
return
70+
} else {
71+
r.Rows[i][index] = uint32(t)
72+
}
6173
case int64:
6274
r.Rows[i][index] = uint64(t)
6375
case int:

go.sum

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
44
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
55
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
66
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
7+
github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8 h1:USx2/E1bX46VG32FIw034Au6seQ2fY9NEILmNh/UlQg=
78
github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8/go.mod h1:B1+S9LNcuMyLH/4HMTViQOJevkGiik3wW2AN9zb2fNQ=
89
github.com/pingcap/errors v0.11.0 h1:DCJQB8jrHbQ1VVlMFIrbj2ApScNNotVmkSNplu2yUt4=
910
github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=

schema/schema.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ var HAHealthCheckSchema = "mysql.ha_health_check"
1919

2020
// Different column type
2121
const (
22-
TYPE_NUMBER = iota + 1 // tinyint, smallint, mediumint, int, bigint, year
22+
TYPE_NUMBER = iota + 1 // tinyint, smallint, int, bigint, year
2323
TYPE_FLOAT // float, double
2424
TYPE_ENUM // enum
2525
TYPE_SET // set
@@ -31,6 +31,7 @@ const (
3131
TYPE_BIT // bit
3232
TYPE_JSON // json
3333
TYPE_DECIMAL // decimal
34+
TYPE_MEDIUM_INT
3435
)
3536

3637
type TableColumn struct {
@@ -105,6 +106,8 @@ func (ta *Table) AddColumn(name string, columnType string, collation string, ext
105106
ta.Columns[index].Type = TYPE_BIT
106107
} else if strings.HasPrefix(columnType, "json") {
107108
ta.Columns[index].Type = TYPE_JSON
109+
} else if strings.Contains(columnType, "mediumint") {
110+
ta.Columns[index].Type = TYPE_MEDIUM_INT
108111
} else if strings.Contains(columnType, "int") || strings.HasPrefix(columnType, "year") {
109112
ta.Columns[index].Type = TYPE_NUMBER
110113
} else {

0 commit comments

Comments
 (0)