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 Jan 15, 2019
1 parent 5118158 commit 8780814
Show file tree
Hide file tree
Showing 4 changed files with 53 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 @@ -996,7 +996,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, errors.Trace(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
35 changes: 35 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3746,3 +3746,38 @@ 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>`,
))

rs, err := tk.Exec(`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.")
c.Assert(rs, IsNil)

rs, err = tk.Exec(`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.")
c.Assert(rs, IsNil)

rs, err = tk.Exec(`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.")
c.Assert(rs, IsNil)

rs, err = tk.Exec(`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.")
c.Assert(rs, IsNil)

rs, err = tk.Exec(`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.")
c.Assert(rs, IsNil)
}
3 changes: 3 additions & 0 deletions planner/core/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const (
codeWrongNumberOfColumnsInSelect = mysql.ErrWrongNumberOfColumnsInSelect
codeWrongValueCountOnRow = mysql.ErrWrongValueCountOnRow
codeTablenameNotAllowedHere = mysql.ErrTablenameNotAllowedHere
codeErrTooBigPrecision = mysql.ErrTooBigPrecision
)

// error definitions.
Expand Down Expand Up @@ -85,6 +86,7 @@ var (
ErrMixOfGroupFuncAndFields = terror.ClassOptimizer.New(codeMixOfGroupFuncAndFields, "In aggregated query without GROUP BY, expression #%d of SELECT list contains nonaggregated column '%s'; this is incompatible with sql_mode=only_full_group_by")
ErrNonUniqTable = terror.ClassOptimizer.New(codeNonUniqTable, mysql.MySQLErrName[mysql.ErrNonuniqTable])
ErrWrongValueCountOnRow = terror.ClassOptimizer.New(mysql.ErrWrongValueCountOnRow, mysql.MySQLErrName[mysql.ErrWrongValueCountOnRow])
errTooBigPrecision = terror.ClassExpression.New(mysql.ErrTooBigPrecision, mysql.MySQLErrName[mysql.ErrTooBigPrecision])
)

func init() {
Expand Down Expand Up @@ -112,6 +114,7 @@ func init() {
codeNonUniqTable: mysql.ErrNonuniqTable,
codeWrongNumberOfColumnsInSelect: mysql.ErrWrongNumberOfColumnsInSelect,
codeWrongValueCountOnRow: mysql.ErrWrongValueCountOnRow,
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 @@ -780,6 +780,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 @@ -808,6 +815,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 8780814

Please sign in to comment.