Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expression: throw "too big precision" error for CAST(AS TIME) #8907

Merged
merged 11 commits into from
Jan 9, 2019
2 changes: 1 addition & 1 deletion expression/builtin_cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -1001,7 +1001,7 @@ func (b *builtinCastDecimalAsDurationSig) Clone() builtinFunc {
func (b *builtinCastDecimalAsDurationSig) evalDuration(row chunk.Row) (res types.Duration, isNull bool, err error) {
val, isNull, err := b.args[0].EvalDecimal(b.ctx, row)
if isNull || err != nil {
return res, false, err
return res, true, err
zz-jason marked this conversation as resolved.
Show resolved Hide resolved
}
res, err = types.ParseDuration(b.ctx.GetSessionVars().StmtCtx, string(val.ToString()), b.tp.Decimal)
if types.ErrTruncatedWrongVal.Equal(err) {
Expand Down
30 changes: 30 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3797,3 +3797,33 @@ func (s *testIntegrationSuite) TestUserVarMockWindFunc(c *C) {
`3 6 3 key3-value6 insert_order6`,
))
}

func (s *testIntegrationSuite) TestCastAsTime(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec(`use test;`)
tk.MustExec(`drop table if exists t;`)
tk.MustExec(`create table t (col1 bigint, col2 double, col3 decimal, col4 varchar(20), col5 json);`)
tk.MustExec(`insert into t values (1, 1, 1, "1", "1");`)
tk.MustExec(`insert into t values (null, null, null, null, null);`)
tk.MustQuery(`select cast(col1 as time), cast(col2 as time), cast(col3 as time), cast(col4 as time), cast(col5 as time) from t where col1 = 1;`).Check(testkit.Rows(
`00:00:01 00:00:01 00:00:01 00:00:01 00:00:01`,
))
tk.MustQuery(`select cast(col1 as time), cast(col2 as time), cast(col3 as time), cast(col4 as time), cast(col5 as time) from t where col1 is null;`).Check(testkit.Rows(
`<nil> <nil> <nil> <nil> <nil>`,
))

err := tk.ExecToErr(`select cast(col1 as time(31)) from t where col1 is null;`)
c.Assert(err.Error(), Equals, "[expression:1426]Too big precision 31 specified for column 'CAST'. Maximum is 6.")

err = tk.ExecToErr(`select cast(col2 as time(31)) from t where col1 is null;`)
c.Assert(err.Error(), Equals, "[expression:1426]Too big precision 31 specified for column 'CAST'. Maximum is 6.")

err = tk.ExecToErr(`select cast(col3 as time(31)) from t where col1 is null;`)
c.Assert(err.Error(), Equals, "[expression:1426]Too big precision 31 specified for column 'CAST'. Maximum is 6.")

err = tk.ExecToErr(`select cast(col4 as time(31)) from t where col1 is null;`)
c.Assert(err.Error(), Equals, "[expression:1426]Too big precision 31 specified for column 'CAST'. Maximum is 6.")

err = tk.ExecToErr(`select cast(col5 as time(31)) from t where col1 is null;`)
c.Assert(err.Error(), Equals, "[expression:1426]Too big precision 31 specified for column 'CAST'. Maximum is 6.")
}
3 changes: 3 additions & 0 deletions planner/core/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const (
codeWindowNoInherentFrame = mysql.ErrWindowNoInherentFrame
codeWindowNoRedefineOrderBy = mysql.ErrWindowNoRedefineOrderBy
codeWindowDuplicateName = mysql.ErrWindowDuplicateName
codeErrTooBigPrecision = mysql.ErrTooBigPrecision
)

// error definitions.
Expand Down Expand Up @@ -106,6 +107,7 @@ var (
ErrWindowNoInherentFrame = terror.ClassOptimizer.New(codeWindowNoInherentFrame, mysql.MySQLErrName[mysql.ErrWindowNoInherentFrame])
ErrWindowNoRedefineOrderBy = terror.ClassOptimizer.New(codeWindowNoRedefineOrderBy, mysql.MySQLErrName[mysql.ErrWindowNoRedefineOrderBy])
ErrWindowDuplicateName = terror.ClassOptimizer.New(codeWindowDuplicateName, mysql.MySQLErrName[mysql.ErrWindowDuplicateName])
errTooBigPrecision = terror.ClassExpression.New(mysql.ErrTooBigPrecision, mysql.MySQLErrName[mysql.ErrTooBigPrecision])
)

func init() {
Expand Down Expand Up @@ -142,6 +144,7 @@ func init() {
codeWindowNoInherentFrame: mysql.ErrWindowNoInherentFrame,
codeWindowNoRedefineOrderBy: mysql.ErrWindowNoRedefineOrderBy,
codeWindowDuplicateName: mysql.ErrWindowDuplicateName,
codeErrTooBigPrecision: mysql.ErrTooBigPrecision,
}
terror.ErrClassToMySQLCodes[terror.ClassOptimizer] = mysqlErrCodeMap
}
14 changes: 14 additions & 0 deletions planner/core/expression_rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,13 @@ func (er *expressionRewriter) Leave(originInNode ast.Node) (retNode ast.Node, ok
if er.err != nil {
return retNode, false
}

// check the decimal precision of "CAST(AS TIME)".
er.err = er.checkTimePrecision(v.Tp)
if er.err != nil {
return retNode, false
}

er.ctxStack[len(er.ctxStack)-1] = expression.BuildCastFunction(er.ctx, arg, v.Tp)
case *ast.PatternLikeExpr:
er.likeToScalarFunc(v)
Expand Down Expand Up @@ -827,6 +834,13 @@ func (er *expressionRewriter) Leave(originInNode ast.Node) (retNode ast.Node, ok
return originInNode, true
}

func (er *expressionRewriter) checkTimePrecision(ft *types.FieldType) error {
if ft.EvalType() == types.ETDuration && ft.Decimal > types.MaxFsp {
return errTooBigPrecision.GenWithStackByArgs(ft.Decimal, "CAST", types.MaxFsp)
}
return nil
}

func (er *expressionRewriter) useCache() bool {
return er.ctx.GetSessionVars().StmtCtx.UseCache
}
Expand Down