diff --git a/mysql/time.go b/mysql/time.go index 7e094a5625..ef3de14509 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 parseDateFormat(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 + } + + // Seperator is a single 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 := parseDateFormat(str) + switch len(seps) { case 1: // No delimiter. 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)