diff --git a/expression/builtin.go b/expression/builtin.go index cb7549f41b587..0cc7756e38f25 100644 --- a/expression/builtin.go +++ b/expression/builtin.go @@ -413,6 +413,7 @@ var funcs = map[string]functionClass{ ast.Year: &yearFunctionClass{baseFunctionClass{ast.Year, 1, 1}}, ast.YearWeek: &yearWeekFunctionClass{baseFunctionClass{ast.YearWeek, 1, 2}}, ast.LastDay: &lastDayFunctionClass{baseFunctionClass{ast.LastDay, 1, 1}}, + ast.TiDBParseTso: &tidbParseTsoFunctionClass{baseFunctionClass{ast.TiDBParseTso, 1, 1}}, // string functions ast.ASCII: &asciiFunctionClass{baseFunctionClass{ast.ASCII, 1, 1}}, diff --git a/expression/builtin_time.go b/expression/builtin_time.go index f25a3f9125f07..46b5b4a1e967d 100644 --- a/expression/builtin_time.go +++ b/expression/builtin_time.go @@ -31,6 +31,7 @@ import ( "github.com/pingcap/parser/terror" "github.com/pingcap/tidb/sessionctx" "github.com/pingcap/tidb/sessionctx/stmtctx" + "github.com/pingcap/tidb/store/tikv/oracle" "github.com/pingcap/tidb/types" "github.com/pingcap/tidb/util/chunk" "github.com/pingcap/tipb/go-tipb" @@ -5652,3 +5653,50 @@ func getExpressionFsp(ctx sessionctx.Context, expression Expression) (int, error } return mathutil.Min(expression.GetType().Decimal, types.MaxFsp), nil } + +//tidbParseTsoFunction extracts physical time from a tso +type tidbParseTsoFunctionClass struct { + baseFunctionClass +} + +func (c *tidbParseTsoFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) { + if err := c.verifyArgs(args); err != nil { + return nil, errors.Trace(err) + } + argTp := args[0].GetType().EvalType() + bf := newBaseBuiltinFuncWithTp(ctx, args, argTp, types.ETInt) + + bf.tp.Tp, bf.tp.Flen, bf.tp.Decimal = mysql.TypeDate, mysql.MaxDateWidth, types.DefaultFsp + sig := &builtinTidbParseTsoSig{bf} + return sig, nil +} + +type builtinTidbParseTsoSig struct { + baseBuiltinFunc +} + +func (b *builtinTidbParseTsoSig) Clone() builtinFunc { + newSig := &builtinTidbParseTsoSig{} + newSig.cloneFrom(&b.baseBuiltinFunc) + return newSig +} + +// evalTime evals a builtinTidbParseTsoSig. +func (b *builtinTidbParseTsoSig) evalTime(row chunk.Row) (types.Time, bool, error) { + arg, isNull, err := b.args[0].EvalInt(b.ctx, row) + if isNull || err != nil || arg <= 0 { + return types.Time{}, true, errors.Trace(handleInvalidTimeError(b.ctx, err)) + } + + t := oracle.GetTimeFromTS(uint64(arg)) + result := types.Time{ + Time: types.FromGoTime(t), + Type: mysql.TypeDatetime, + Fsp: types.MaxFsp, + } + err = result.ConvertTimeZone(time.Local, b.ctx.GetSessionVars().Location()) + if err != nil { + return types.Time{}, true, errors.Trace(err) + } + return result, false, nil +} diff --git a/expression/builtin_time_test.go b/expression/builtin_time_test.go index 844e4e759c410..bb4bb615224df 100644 --- a/expression/builtin_time_test.go +++ b/expression/builtin_time_test.go @@ -2389,3 +2389,40 @@ func (s *testEvaluatorSuite) TestWithTimeZone(c *C) { c.Assert(result.Sub(now), LessEqual, 2*time.Second) } } + +func (s *testEvaluatorSuite) TestTidbParseTso(c *C) { + s.ctx.GetSessionVars().TimeZone = time.UTC + tests := []struct { + param interface{} + expect string + }{ + {404411537129996288, "2018-11-20 09:53:04.877000"}, + {"404411537129996288", "2018-11-20 09:53:04.877000"}, + {1, "1970-01-01 00:00:00.000000"}, + } + + fc := funcs[ast.TiDBParseTso] + for _, test := range tests { + t := []types.Datum{types.NewDatum(test.param)} + f, err := fc.getFunction(s.ctx, s.datumsToConstants(t)) + c.Assert(err, IsNil) + d, err := evalBuiltinFunc(f, chunk.Row{}) + c.Assert(err, IsNil) + result, _ := d.ToString() + c.Assert(result, Equals, test.expect) + } + + testsNull := []interface{}{ + 0, + -1, + "-1"} + + for _, i := range testsNull { + t := []types.Datum{types.NewDatum(i)} + f, err := fc.getFunction(s.ctx, s.datumsToConstants(t)) + c.Assert(err, IsNil) + d, err := evalBuiltinFunc(f, chunk.Row{}) + c.Assert(err, IsNil) + c.Assert(d.IsNull(), IsTrue) + } +} diff --git a/expression/integration_test.go b/expression/integration_test.go index ba5da327f80c8..b46ae9111cc3e 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -1831,6 +1831,19 @@ func (s *testIntegrationSuite) TestTimeBuiltin(c *C) { // for current_timestamp, current_timestamp() result = tk.MustQuery(`select current_timestamp() = now(), current_timestamp = now()`) result.Check(testkit.Rows("1 1")) + + // for tidb_parse_tso + tk.MustExec("SET time_zone = '+00:00';") + result = tk.MustQuery(`select tidb_parse_tso(404411537129996288)`) + result.Check(testkit.Rows("2018-11-20 09:53:04.877000")) + result = tk.MustQuery(`select tidb_parse_tso("404411537129996288")`) + result.Check(testkit.Rows("2018-11-20 09:53:04.877000")) + result = tk.MustQuery(`select tidb_parse_tso(1)`) + result.Check(testkit.Rows("1970-01-01 00:00:00.000000")) + result = tk.MustQuery(`select tidb_parse_tso(0)`) + result.Check(testkit.Rows("")) + result = tk.MustQuery(`select tidb_parse_tso(-1)`) + result.Check(testkit.Rows("")) } func (s *testIntegrationSuite) TestOpBuiltin(c *C) { diff --git a/go.mod b/go.mod index c4b6fdbda7b9c..36ba9c8ab39d5 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/pingcap/errors v0.11.0 github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e github.com/pingcap/kvproto v0.0.0-20181105061835-1b5d69cd1d26 - github.com/pingcap/parser v0.0.0-20181120072820-10951bcfca73 + github.com/pingcap/parser v0.0.0-20181126111651-a38036a60de7 github.com/pingcap/pd v2.1.0-rc.4+incompatible github.com/pingcap/tidb-tools v0.0.0-20181112132202-4860a0d5de03 github.com/pingcap/tipb v0.0.0-20181012112600-11e33c750323 diff --git a/go.sum b/go.sum index 2fd165738ab9c..88fef10e54a99 100644 --- a/go.sum +++ b/go.sum @@ -209,6 +209,8 @@ github.com/pingcap/parser v0.0.0-20181113072426-4a9a1b13b591 h1:7lErVcNwgmWNgsZw github.com/pingcap/parser v0.0.0-20181113072426-4a9a1b13b591/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA= github.com/pingcap/parser v0.0.0-20181120072820-10951bcfca73 h1:toHh8VsVgJTP9A4O/BO73T3i8RpvRTwuS9eMe7pZUK0= github.com/pingcap/parser v0.0.0-20181120072820-10951bcfca73/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA= +github.com/pingcap/parser v0.0.0-20181126111651-a38036a60de7 h1:E/T5kIrtzipWJhN/YREI+f3PiP6Uw5boE4KRcD+zVvo= +github.com/pingcap/parser v0.0.0-20181126111651-a38036a60de7/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA= github.com/pingcap/pd v0.0.0-20180619050643-0ec6ffcf94e8/go.mod h1:nD3+EoYes4+aNNODO99ES59V83MZSI+dFbhyr667a0E= github.com/pingcap/pd v0.0.0-20181015053559-eb892dda1e33 h1:UQKEV9u9PR1RjFiJqqGijsHAEzTDZe89xdgB4Lj9S8Y= github.com/pingcap/pd v0.0.0-20181015053559-eb892dda1e33/go.mod h1:+bFEXnol47I8RhLpb0RbP5ZvpG6Ca7dw0LL/ARsmRk0=