Skip to content

Commit 6d16046

Browse files
committed
replication: return string when datetime's day or month is 00
MySQL supports 0 for day/month when this is an unknown value This cannot be encoded into a time.Time, where time.Date normalizes these 0s (so 2000-00-00 would become 1999-11-30) Pass these values through in their raw string form instead
1 parent 447a516 commit 6d16046

File tree

2 files changed

+29
-16
lines changed

2 files changed

+29
-16
lines changed

replication/row_event.go

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,7 +1316,7 @@ func (e *RowsEvent) decodeValue(data []byte, tp byte, meta uint16, isPartial boo
13161316
n = 4
13171317
t := binary.LittleEndian.Uint32(data)
13181318
if t == 0 {
1319-
v = formatZeroTime(0, 0)
1319+
v = "0000-00-00 00:00:00"
13201320
} else {
13211321
v = e.parseFracTime(fracTime{
13221322
Time: time.Unix(int64(t), 0),
@@ -1331,23 +1331,34 @@ func (e *RowsEvent) decodeValue(data []byte, tp byte, meta uint16, isPartial boo
13311331
n = 8
13321332
i64 := binary.LittleEndian.Uint64(data)
13331333
if i64 == 0 {
1334-
v = formatZeroTime(0, 0)
1334+
v = "0000-00-00 00:00:00"
13351335
} else {
13361336
d := i64 / 1000000
13371337
t := i64 % 1000000
1338-
v = e.parseFracTime(fracTime{
1339-
Time: time.Date(
1340-
int(d/10000),
1341-
time.Month((d%10000)/100),
1342-
int(d%100),
1343-
int(t/10000),
1344-
int((t%10000)/100),
1345-
int(t%100),
1346-
0,
1347-
time.UTC,
1348-
),
1349-
Dec: 0,
1350-
})
1338+
years := int(d / 10000)
1339+
months := (d % 10000) / 100
1340+
days := int(d % 100)
1341+
hours := int(t / 10000)
1342+
minutes := int((t % 10000) / 100)
1343+
seconds := int(t % 100)
1344+
if months == 0 || days == 0 {
1345+
v = fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d",
1346+
years, months, days, hours, minutes, seconds)
1347+
} else {
1348+
v = e.parseFracTime(fracTime{
1349+
Time: time.Date(
1350+
int(d/10000),
1351+
time.Month((d%10000)/100),
1352+
int(d%100),
1353+
int(t/10000),
1354+
int((t%10000)/100),
1355+
int(t%100),
1356+
0,
1357+
time.UTC,
1358+
),
1359+
Dec: 0,
1360+
})
1361+
}
13511362
}
13521363
case mysql.MYSQL_TYPE_DATETIME2:
13531364
v, n, err = decodeDatetime2(data, meta)
@@ -1725,7 +1736,7 @@ func decodeDatetime2(data []byte, dec uint16) (interface{}, int, error) {
17251736
// minute = 0 = 0b000000
17261737
// second = 0 = 0b000000
17271738
// integer value = 0b1100100000010110000100000000000000000 = 107420450816
1728-
if intPart < 107420450816 {
1739+
if intPart < 107420450816 || month == 0 || day == 0 {
17291740
return formatBeforeUnixZeroTime(year, month, day, hour, minute, second, int(frac), int(dec)), n, nil
17301741
}
17311742

replication/row_event_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,8 @@ func TestDecodeDatetime2(t *testing.T) {
675675
}{
676676
{[]byte("\xfe\xf3\xff\x7e\xfb"), 0, true, "9999-12-31 23:59:59"},
677677
{[]byte("\x99\x9a\xb8\xf7\xaa"), 0, true, "2016-10-28 15:30:42"},
678+
{[]byte("\x99\x98\x38\xf7\xaa"), 0, false, "2016-00-28 15:30:42"},
679+
{[]byte("\x99\x9a\x80\xf7\xaa"), 0, false, "2016-10-00 15:30:42"},
678680
{[]byte("\x99\x02\xc2\x00\x00"), 0, true, "1970-01-01 00:00:00"},
679681
{[]byte("\x80\x00\x00\x00\x00"), 0, false, "0000-00-00 00:00:00"},
680682
{[]byte("\x80\x00\x02\xf1\x05"), 0, false, "0000-00-01 15:04:05"},

0 commit comments

Comments
 (0)