Skip to content

Commit

Permalink
expression: throw "too big precision" error for CAST(AS TIME) (#8907)
Browse files Browse the repository at this point in the history
  • Loading branch information
zz-jason authored and ngaut committed Jan 9, 2019
1 parent bb2d56a commit 0bc0f7d
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 1 deletion.
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
}
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

0 comments on commit 0bc0f7d

Please sign in to comment.