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) #9058

Merged
merged 3 commits into from Jan 15, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion expression/builtin_cast.go
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
30 changes: 30 additions & 0 deletions expression/integration_test.go
Expand Up @@ -3746,3 +3746,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
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
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