1
0
Fork 0

Get rid of FracTime and friends

This commit is contained in:
Gregory Eremin 2018-11-19 22:56:31 +01:00
parent db67e68078
commit 83e16c72f2
3 changed files with 93 additions and 116 deletions

View File

@ -5,7 +5,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"runtime/debug" "runtime/debug"
"time"
"github.com/localhots/bocadillo/mysql" "github.com/localhots/bocadillo/mysql"
"github.com/localhots/bocadillo/tools" "github.com/localhots/bocadillo/tools"
@ -191,8 +190,9 @@ func (e *RowsEvent) decodeValue(buf *tools.Buffer, ct mysql.ColumnType, meta uin
buf.Skip(n) buf.Skip(n)
return v return v
case mysql.ColumnTypeTimestamp: case mysql.ColumnTypeTimestamp:
ts := buf.ReadUint32() v, n := mysql.DecodeTimestamp(buf.Cur(), meta)
return mysql.FracTime{Time: time.Unix(int64(ts), 0)}.String() buf.Skip(n)
return v
case mysql.ColumnTypeTimestamp2: case mysql.ColumnTypeTimestamp2:
v, n := mysql.DecodeTimestamp2(buf.Cur(), meta) v, n := mysql.DecodeTimestamp2(buf.Cur(), meta)
buf.Skip(n) buf.Skip(n)

View File

@ -103,10 +103,17 @@ func DecodeTime2(data []byte, dec uint16) (string, int) {
return fmt.Sprintf("%s%02d:%02d:%02d", sign, hour, minute, second), n return fmt.Sprintf("%s%02d:%02d:%02d", sign, hour, minute, second), n
} }
// DecodeTimestamp decodes TIMESTAMP value.
// Spec: https://dev.mysql.com/doc/refman/8.0/en/datetime.html
// Implementation borrowed from https://github.com/siddontang/go-mysql/
func DecodeTimestamp(data []byte, dec uint16) (time.Time, int) {
return time.Unix(int64(DecodeUint32(data)), 0), 4
}
// DecodeTimestamp2 decodes TIMESTAMP v2 value. // DecodeTimestamp2 decodes TIMESTAMP v2 value.
// Spec: https://dev.mysql.com/doc/refman/8.0/en/datetime.html // Spec: https://dev.mysql.com/doc/refman/8.0/en/datetime.html
// Implementation borrowed from https://github.com/siddontang/go-mysql/ // Implementation borrowed from https://github.com/siddontang/go-mysql/
func DecodeTimestamp2(data []byte, dec uint16) (string, int) { func DecodeTimestamp2(data []byte, dec uint16) (time.Time, int) {
// get timestamp binary length // get timestamp binary length
n := int(4 + (dec+1)/2) n := int(4 + (dec+1)/2)
sec := int64(binary.BigEndian.Uint32(data[0:4])) sec := int64(binary.BigEndian.Uint32(data[0:4]))
@ -121,18 +128,18 @@ func DecodeTimestamp2(data []byte, dec uint16) (string, int) {
} }
if sec == 0 { if sec == 0 {
return formatZeroTime(int(usec), int(dec)), n return time.Time{}, n
} }
return FracTime{time.Unix(sec, usec*1000), int(dec)}.String(), n return time.Unix(sec, usec*1000), n
} }
// DecodeDatetime decodes DATETIME value. // DecodeDatetime decodes DATETIME value.
// Spec: https://dev.mysql.com/doc/refman/8.0/en/datetime.html // Spec: https://dev.mysql.com/doc/refman/8.0/en/datetime.html
func DecodeDatetime(v uint64) string { func DecodeDatetime(v uint64) time.Time {
d := v / 1000000 d := v / 1000000
t := v % 1000000 t := v % 1000000
return FracTime{Time: time.Date(int(d/10000), return time.Date(int(d/10000),
time.Month((d%10000)/100), time.Month((d%10000)/100),
int(d%100), int(d%100),
int(t/10000), int(t/10000),
@ -140,13 +147,13 @@ func DecodeDatetime(v uint64) string {
int(t%100), int(t%100),
0, 0,
Timezone, Timezone,
)}.String() )
} }
// DecodeDatetime2 decodes DATETIME v2 value. // DecodeDatetime2 decodes DATETIME v2 value.
// Spec: https://dev.mysql.com/doc/refman/8.0/en/datetime.html // Spec: https://dev.mysql.com/doc/refman/8.0/en/datetime.html
// Implementation borrowed from https://github.com/siddontang/go-mysql/ // Implementation borrowed from https://github.com/siddontang/go-mysql/
func DecodeDatetime2(data []byte, dec uint16) (string, int) { func DecodeDatetime2(data []byte, dec uint16) (time.Time, int) {
const offset int64 = 0x8000000000 const offset int64 = 0x8000000000
// get datetime binary length // get datetime binary length
n := int(5 + (dec+1)/2) n := int(5 + (dec+1)/2)
@ -164,7 +171,7 @@ func DecodeDatetime2(data []byte, dec uint16) (string, int) {
} }
if intPart == 0 { if intPart == 0 {
return formatZeroTime(int(frac), int(dec)), n return time.Time{}, n
} }
tmp := intPart<<24 + frac tmp := intPart<<24 + frac
@ -188,41 +195,5 @@ func DecodeDatetime2(data []byte, dec uint16) (string, int) {
minute := int((hms >> 6) % (1 << 6)) minute := int((hms >> 6) % (1 << 6))
hour := int((hms >> 12)) hour := int((hms >> 12))
return FracTime{time.Date(year, time.Month(month), day, hour, minute, second, int(frac*1000), Timezone), int(dec)}.String(), n return time.Date(year, time.Month(month), day, hour, minute, second, int(frac*1000), Timezone), n
}
var (
fracTimeFormat = [...]string{
"2006-01-02T15:04:05Z",
"2006-01-02T15:04:05.0Z",
"2006-01-02T15:04:05.00Z",
"2006-01-02T15:04:05.000Z",
"2006-01-02T15:04:05.0000Z",
"2006-01-02T15:04:05.00000Z",
"2006-01-02T15:04:05.000000Z",
}
zeroTimes = [...]string{
"0000-00-00T00:00:00Z",
"0000-00-00T00:00:00.0Z",
"0000-00-00T00:00:00.00Z",
"0000-00-00T00:00:00.000Z",
"0000-00-00T00:00:00.0000Z",
"0000-00-00T00:00:00.00000Z",
"0000-00-00T00:00:00.000000Z",
}
)
// FracTime is a help structure wrapping Golang Time.
type FracTime struct {
time.Time
Dec int
}
func (t FracTime) String() string {
return t.Format(fracTimeFormat[t.Dec])
}
func formatZeroTime(frac int, dec int) string {
// We are going to ignore frac/dec distinction here
return zeroTimes[dec]
} }

View File

@ -3,6 +3,7 @@ package tests
import ( import (
"fmt" "fmt"
"testing" "testing"
"time"
"github.com/localhots/bocadillo/mysql" "github.com/localhots/bocadillo/mysql"
) )
@ -61,96 +62,96 @@ func TestTimestamp(t *testing.T) {
tbl := suite.createTable(mysql.ColumnTypeTimestamp, "", attrNone) tbl := suite.createTable(mysql.ColumnTypeTimestamp, "", attrNone)
defer tbl.drop(t) defer tbl.drop(t)
vals := []string{ vals := []time.Time{
"0000-00-00T00:00:00Z", parseTime("0000-00-00T00:00:00Z"),
// This is the lowest I could get // This is the lowest I could get
// Spec says 1970-01-01 00:00:01 should be supported // Spec says 1970-01-01 00:00:01 should be supported
"1970-01-01T01:00:01Z", parseTime("1970-01-01T01:00:01Z"),
"1975-01-01T00:00:01Z", parseTime("1975-01-01T00:00:01Z"),
"1985-01-01T00:00:01Z", parseTime("1985-01-01T00:00:01Z"),
"1999-12-31T23:59:59Z", parseTime("1999-12-31T23:59:59Z"),
"2018-11-08T19:26:00Z", parseTime("2018-11-08T19:26:00Z"),
"2038-01-19T03:14:07Z", parseTime("2038-01-19T03:14:07Z"),
"2038-01-19T04:14:07Z", // Should be outside supported range? 2038-01-19 03:14:07 parseTime("2038-01-19T04:14:07Z"), // Should be outside supported range? 2038-01-19 03:14:07
} }
for _, v := range vals { for _, v := range vals {
t.Run(v, func(t *testing.T) { t.Run(v.Format(time.RFC3339Nano), func(t *testing.T) {
suite.insertAndCompare(t, tbl, v) suite.insertAndCompare(t, tbl, v)
}) })
} }
} }
func TestDatetime(t *testing.T) { func TestDatetime(t *testing.T) {
inputs := map[string][]string{ inputs := map[string][]time.Time{
"0": { "0": {
"0000-00-00T00:00:00Z", parseTime("0000-00-00T00:00:00Z"),
"1000-01-01T00:00:00Z", parseTime("1000-01-01T00:00:00Z"),
"1975-01-01T00:00:01Z", parseTime("1975-01-01T00:00:01Z"),
"1985-01-01T00:00:01Z", parseTime("1985-01-01T00:00:01Z"),
"1999-12-31T23:59:59Z", parseTime("1999-12-31T23:59:59Z"),
"2018-11-08T19:26:00Z", parseTime("2018-11-08T19:26:00Z"),
"2038-01-19T03:14:07Z", parseTime("2038-01-19T03:14:07Z"),
"9999-12-31T23:59:59Z", parseTime("9999-12-31T23:59:59Z"),
}, },
"1": { "1": {
"0000-00-00T00:00:00.0Z", parseTime("0000-00-00T00:00:00.0Z"),
"1000-01-01T00:00:00.1Z", parseTime("1000-01-01T00:00:00.1Z"),
"1975-01-01T00:00:01.1Z", parseTime("1975-01-01T00:00:01.1Z"),
"1985-01-01T00:00:01.1Z", parseTime("1985-01-01T00:00:01.1Z"),
"1999-12-31T23:59:59.1Z", parseTime("1999-12-31T23:59:59.1Z"),
"2018-11-08T19:26:00.1Z", parseTime("2018-11-08T19:26:00.1Z"),
"2038-01-19T03:14:07.1Z", parseTime("2038-01-19T03:14:07.1Z"),
"9999-12-31T23:59:59.1Z", parseTime("9999-12-31T23:59:59.1Z"),
}, },
"2": { "2": {
"0000-00-00T00:00:00.00Z", parseTime("0000-00-00T00:00:00.00Z"),
"1000-01-01T00:00:00.22Z", parseTime("1000-01-01T00:00:00.22Z"),
"1975-01-01T00:00:01.22Z", parseTime("1975-01-01T00:00:01.22Z"),
"1985-01-01T00:00:01.22Z", parseTime("1985-01-01T00:00:01.22Z"),
"1999-12-31T23:59:59.22Z", parseTime("1999-12-31T23:59:59.22Z"),
"2018-11-08T19:26:00.22Z", parseTime("2018-11-08T19:26:00.22Z"),
"2038-01-19T03:14:07.22Z", parseTime("2038-01-19T03:14:07.22Z"),
"9999-12-31T23:59:59.22Z", parseTime("9999-12-31T23:59:59.22Z"),
}, },
"3": { "3": {
"0000-00-00T00:00:00.000Z", parseTime("0000-00-00T00:00:00.000Z"),
"1000-01-01T00:00:00.333Z", parseTime("1000-01-01T00:00:00.333Z"),
"1975-01-01T00:00:01.333Z", parseTime("1975-01-01T00:00:01.333Z"),
"1985-01-01T00:00:01.333Z", parseTime("1985-01-01T00:00:01.333Z"),
"1999-12-31T23:59:59.333Z", parseTime("1999-12-31T23:59:59.333Z"),
"2018-11-08T19:26:00.333Z", parseTime("2018-11-08T19:26:00.333Z"),
"2038-01-19T03:14:07.333Z", parseTime("2038-01-19T03:14:07.333Z"),
"9999-12-31T23:59:59.333Z", parseTime("9999-12-31T23:59:59.333Z"),
}, },
"4": { "4": {
"0000-00-00T00:00:00.0000Z", parseTime("0000-00-00T00:00:00.0000Z"),
"1000-01-01T00:00:00.4444Z", parseTime("1000-01-01T00:00:00.4444Z"),
"1975-01-01T00:00:01.4444Z", parseTime("1975-01-01T00:00:01.4444Z"),
"1985-01-01T00:00:01.4444Z", parseTime("1985-01-01T00:00:01.4444Z"),
"1999-12-31T23:59:59.4444Z", parseTime("1999-12-31T23:59:59.4444Z"),
"2018-11-08T19:26:00.4444Z", parseTime("2018-11-08T19:26:00.4444Z"),
"2038-01-19T03:14:07.4444Z", parseTime("2038-01-19T03:14:07.4444Z"),
"9999-12-31T23:59:59.4444Z", parseTime("9999-12-31T23:59:59.4444Z"),
}, },
"5": { "5": {
"0000-00-00T00:00:00.00000Z", parseTime("0000-00-00T00:00:00.00000Z"),
"1000-01-01T00:00:00.55555Z", parseTime("1000-01-01T00:00:00.55555Z"),
"1975-01-01T00:00:01.55555Z", parseTime("1975-01-01T00:00:01.55555Z"),
"1985-01-01T00:00:01.55555Z", parseTime("1985-01-01T00:00:01.55555Z"),
"1999-12-31T23:59:59.55555Z", parseTime("1999-12-31T23:59:59.55555Z"),
"2018-11-08T19:26:00.55555Z", parseTime("2018-11-08T19:26:00.55555Z"),
"2038-01-19T03:14:07.55555Z", parseTime("2038-01-19T03:14:07.55555Z"),
"9999-12-31T23:59:59.55555Z", parseTime("9999-12-31T23:59:59.55555Z"),
}, },
"6": { "6": {
"0000-00-00T00:00:00.000000Z", parseTime("0000-00-00T00:00:00.000000Z"),
"1000-01-01T00:00:00.666666Z", parseTime("1000-01-01T00:00:00.666666Z"),
"1975-01-01T00:00:01.666666Z", parseTime("1975-01-01T00:00:01.666666Z"),
"1985-01-01T00:00:01.666666Z", parseTime("1985-01-01T00:00:01.666666Z"),
"1999-12-31T23:59:59.666666Z", parseTime("1999-12-31T23:59:59.666666Z"),
"2018-11-08T19:26:00.666666Z", parseTime("2018-11-08T19:26:00.666666Z"),
"2038-01-19T03:14:07.666666Z", parseTime("2038-01-19T03:14:07.666666Z"),
"9999-12-31T23:59:59.666666Z", parseTime("9999-12-31T23:59:59.666666Z"),
}, },
} }
for length, vals := range inputs { for length, vals := range inputs {
@ -159,10 +160,15 @@ func TestDatetime(t *testing.T) {
defer tbl.drop(t) defer tbl.drop(t)
for _, v := range vals { for _, v := range vals {
t.Run(v, func(t *testing.T) { t.Run(v.Format(time.RFC3339Nano), func(t *testing.T) {
suite.insertAndCompare(t, tbl, v) suite.insertAndCompare(t, tbl, v)
}) })
} }
}) })
} }
} }
func parseTime(str string) time.Time {
t, _ := time.Parse(str, time.RFC3339Nano)
return t
}