From e4b687858a5dccb3cf50b3ac381c0efc586a47aa Mon Sep 17 00:00:00 2001 From: qiuyesuifeng Date: Thu, 22 Oct 2015 13:17:48 +0800 Subject: [PATCH 1/4] mysql: update parseDatetime format. --- mysql/time.go | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/mysql/time.go b/mysql/time.go index 7e094a5625..612284dee0 100644 --- a/mysql/time.go +++ b/mysql/time.go @@ -310,14 +310,41 @@ func (t Time) RoundFrac(fsp int) (Time, error) { return Time{Time: nt, Type: t.Type, Fsp: fsp}, nil } +func parseDateFromat(format string) []string { + format = strings.TrimSpace(format) + + start := 0 + seps := []string{} + for i := 0; i < len(format); i++ { + // Date fromat must start and end with number. + if i == 0 || i == len(format)-1 { + if !unicode.IsNumber(rune(format[i])) { + return nil + } + + continue + } + + // Sep can be only one none-number char. + if !unicode.IsNumber(rune(format[i])) { + if !unicode.IsNumber(rune(format[i-1])) { + return nil + } + + seps = append(seps, format[start:i]) + start = i + 1 + } + + } + + seps = append(seps, format[start:]) + return seps +} + func parseDatetime(str string, fsp int) (Time, error) { // Try to split str with delimiter. // TODO: only punctuation can be the delimiter for date parts or time parts. // But only space and T can be the delimiter between the date and time part. - seps := strings.FieldsFunc(str, func(c rune) bool { - return !unicode.IsNumber(c) - }) - var ( year int month int @@ -330,6 +357,9 @@ func parseDatetime(str string, fsp int) (Time, error) { err error ) + + seps := parseDateFromat(str) + switch len(seps) { case 1: // No delimiter. From 4d777a841d4ee0bd169dc9243ac6e0ae2574a060 Mon Sep 17 00:00:00 2001 From: qiuyesuifeng Date: Thu, 22 Oct 2015 13:32:29 +0800 Subject: [PATCH 2/4] mysql: typo. --- mysql/time.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql/time.go b/mysql/time.go index 612284dee0..4fdf6db244 100644 --- a/mysql/time.go +++ b/mysql/time.go @@ -310,7 +310,7 @@ func (t Time) RoundFrac(fsp int) (Time, error) { return Time{Time: nt, Type: t.Type, Fsp: fsp}, nil } -func parseDateFromat(format string) []string { +func parseDateFormat(format string) []string { format = strings.TrimSpace(format) start := 0 @@ -358,7 +358,7 @@ func parseDatetime(str string, fsp int) (Time, error) { err error ) - seps := parseDateFromat(str) + seps := parseDateFormat(str) switch len(seps) { case 1: From 017389e93b5f413db2e6a9b767d191172a2086c0 Mon Sep 17 00:00:00 2001 From: qiuyesuifeng Date: Thu, 22 Oct 2015 13:32:55 +0800 Subject: [PATCH 3/4] *: add tests. --- mysql/time_test.go | 23 +++++++++++++++++++++++ tidb_test.go | 8 ++++++++ 2 files changed, 31 insertions(+) diff --git a/mysql/time_test.go b/mysql/time_test.go index f58851ace2..1f11d3a614 100644 --- a/mysql/time_test.go +++ b/mysql/time_test.go @@ -671,3 +671,26 @@ func (s *testTimeSuite) TestDurationClock(c *C) { c.Assert(d.MicroSecond(), Equals, t.MicroSecond) } } + +func (s *testTimeSuite) TestParseDateFormat(c *C) { + tbl := []struct { + Input string + Result []string + }{ + {"2011-11-11 10:10:10.123456", []string{"2011", "11", "11", "10", "10", "10", "123456"}}, + {" 2011-11-11 10:10:10.123456 ", []string{"2011", "11", "11", "10", "10", "10", "123456"}}, + {"2011-11-11 10", []string{"2011", "11", "11", "10"}}, + {"2011-11-11T10:10:10.123456", []string{"2011", "11", "11", "10", "10", "10", "123456"}}, + {"2011:11:11T10:10:10.123456", []string{"2011", "11", "11", "10", "10", "10", "123456"}}, + {"xx2011-11-11 10:10:10", nil}, + {"T10:10:10", nil}, + {"2011-11-11x", nil}, + {"2011-11-11 10:10:10", nil}, + {"xxx 10:10:10", nil}, + } + + for _, t := range tbl { + r := parseDateFormat(t.Input) + c.Assert(r, DeepEquals, t.Result) + } +} diff --git a/tidb_test.go b/tidb_test.go index ebfad85886..133cced270 100644 --- a/tidb_test.go +++ b/tidb_test.go @@ -1245,6 +1245,14 @@ func (s *testSessionSuite) TestResultType(c *C) { c.Assert(fs[0].Col.FieldType.Tp, Equals, mysql.TypeString) } +func (s *testSessionSuite) TestBuiltin(c *C) { + store := newStore(c, s.dbName) + se := newSession(c, store, s.dbName) + + // Testcase for https://github.com/pingcap/tidb/issues/382 + mustExecFailed(c, se, `select cast("xxx 10:10:10" as datetime)`) +} + func newSession(c *C, store kv.Storage, dbName string) Session { se, err := CreateSession(store) c.Assert(err, IsNil) From fc6e4ec461179b057037e391fa8c7420e138fe5a Mon Sep 17 00:00:00 2001 From: qiuyesuifeng Date: Mon, 26 Oct 2015 20:45:22 +0800 Subject: [PATCH 4/4] mysql: address comment. --- mysql/time.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql/time.go b/mysql/time.go index 4fdf6db244..ef3de14509 100644 --- a/mysql/time.go +++ b/mysql/time.go @@ -325,7 +325,7 @@ func parseDateFormat(format string) []string { continue } - // Sep can be only one none-number char. + // Seperator is a single none-number char. if !unicode.IsNumber(rune(format[i])) { if !unicode.IsNumber(rune(format[i-1])) { return nil