Skip to content

Commit

Permalink
pkg/expression: fix errors setting date and time precision match mysql
Browse files Browse the repository at this point in the history
ref #56451
  • Loading branch information
chagelo committed Oct 14, 2024
1 parent 74034d4 commit 33af583
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 57 deletions.
4 changes: 2 additions & 2 deletions errors.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2018,7 +2018,7 @@ Division by 0

["expression:1426"]
error = '''
Too big precision %d specified for column '%-.192s'. Maximum is %d.
Too-big precision %d specified for '%-.192s'. Maximum is %d.
'''

["expression:1582"]
Expand Down Expand Up @@ -3288,7 +3288,7 @@ Too big scale %d specified for column '%-.192s'. Maximum is %d.

["types:1426"]
error = '''
Too big precision %d specified for column '%-.192s'. Maximum is %d.
Too-big precision %d specified for '%-.192s'. Maximum is %d.
'''

["types:1427"]
Expand Down
2 changes: 1 addition & 1 deletion pkg/errno/errname.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ var MySQLErrName = map[uint16]*mysql.ErrMessage{
ErrNoDefaultForViewField: mysql.Message("Field of view '%-.192s.%-.192s' underlying table doesn't have a default value", nil),
ErrSpNoRecursion: mysql.Message("Recursive stored functions and triggers are not allowed.", nil),
ErrTooBigScale: mysql.Message("Too big scale %d specified for column '%-.192s'. Maximum is %d.", nil),
ErrTooBigPrecision: mysql.Message("Too big precision %d specified for column '%-.192s'. Maximum is %d.", nil),
ErrTooBigPrecision: mysql.Message("Too-big precision %d specified for '%-.192s'. Maximum is %d.", nil),
ErrMBiggerThanD: mysql.Message("For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.192s').", nil),
ErrWrongLockOfSystemTable: mysql.Message("You can't combine write-locking of system tables with other tables or lock types", nil),
ErrConnectToForeignDataSource: mysql.Message("Unable to connect to foreign data source: %.64s", nil),
Expand Down
57 changes: 30 additions & 27 deletions pkg/expression/builtin_time.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
"github.com/pingcap/tidb/pkg/parser/terror"
"github.com/pingcap/tidb/pkg/sessionctx/stmtctx"
"github.com/pingcap/tidb/pkg/types"
"github.com/pingcap/tidb/pkg/util"
"github.com/pingcap/tidb/pkg/util/chunk"
"github.com/pingcap/tidb/pkg/util/logutil"
"github.com/pingcap/tidb/pkg/util/mathutil"
Expand Down Expand Up @@ -2013,7 +2014,7 @@ func (c *sysDateFunctionClass) getFunction(ctx BuildContext, args []Expression)
if err := c.verifyArgs(args); err != nil {
return nil, err
}
fsp, err := getFspByIntArg(ctx, args)
fsp, err := getFspByIntArg(ctx, args, c.funcName)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -2138,7 +2139,7 @@ func (c *currentTimeFunctionClass) getFunction(ctx BuildContext, args []Expressi
return nil, err
}

fsp, err := getFspByIntArg(ctx, args)
fsp, err := getFspByIntArg(ctx, args, c.funcName)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -2383,7 +2384,7 @@ func (c *utcTimestampFunctionClass) getFunction(ctx BuildContext, args []Express
return nil, err
}

fsp, err := getFspByIntArg(ctx, args)
fsp, err := getFspByIntArg(ctx, args, c.funcName)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -2424,19 +2425,20 @@ func (b *builtinUTCTimestampWithArgSig) Clone() builtinFunc {
// evalTime evals UTC_TIMESTAMP(fsp).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_utc-timestamp
func (b *builtinUTCTimestampWithArgSig) evalTime(ctx EvalContext, row chunk.Row) (types.Time, bool, error) {
num, isNull, err := b.args[0].EvalInt(ctx, row)
fsp, isNull, err := b.args[0].EvalInt(ctx, row)
if err != nil {
return types.ZeroTime, true, err
}

if !isNull && num > int64(types.MaxFsp) {
return types.ZeroTime, true, errors.Errorf("Too-big precision %v specified for 'utc_timestamp'. Maximum is %v", num, types.MaxFsp)
}
if !isNull && num < int64(types.MinFsp) {
return types.ZeroTime, true, errors.Errorf("Invalid negative %d specified, must in [0, 6]", num)
if !isNull {
if fsp > math.MaxInt32 || fsp < types.MinFsp {
return types.ZeroTime, true, types.ErrSyntax.GenWithStack(util.SyntaxErrorPrefix)
} else if fsp > types.MaxFsp {
return types.ZeroTime, true, types.ErrTooBigPrecision.GenWithStackByArgs(fsp, "utc_timestamp", types.MaxFsp)
}
}

result, isNull, err := evalUTCTimestampWithFsp(ctx, int(num))
result, isNull, err := evalUTCTimestampWithFsp(ctx, int(fsp))
return result, isNull, err
}

Expand Down Expand Up @@ -2474,7 +2476,7 @@ func (c *nowFunctionClass) getFunction(ctx BuildContext, args []Expression) (bui
return nil, err
}

fsp, err := getFspByIntArg(ctx, args)
fsp, err := getFspByIntArg(ctx, args, c.funcName)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -2553,10 +2555,10 @@ func (b *builtinNowWithArgSig) evalTime(ctx EvalContext, row chunk.Row) (types.T

if isNull {
fsp = 0
} else if fsp > int64(types.MaxFsp) {
return types.ZeroTime, true, errors.Errorf("Too-big precision %v specified for 'now'. Maximum is %v", fsp, types.MaxFsp)
} else if fsp < int64(types.MinFsp) {
return types.ZeroTime, true, errors.Errorf("Invalid negative %d specified, must in [0, 6]", fsp)
} else if fsp > math.MaxInt32 || fsp < types.MinFsp {
return types.ZeroTime, true, types.ErrSyntax.GenWithStack(util.SyntaxErrorPrefix)
} else if fsp > types.MaxFsp {
return types.ZeroTime, true, types.ErrTooBigPrecision.GenWithStackByArgs(fsp, "now", types.MaxFsp)
}

result, isNull, err := evalNowWithFsp(ctx, int(fsp))
Expand Down Expand Up @@ -6455,7 +6457,7 @@ func (c *utcTimeFunctionClass) getFunction(ctx BuildContext, args []Expression)
if err != nil {
return nil, err
}
fsp, err := getFspByIntArg(ctx, args)
fsp, err := getFspByIntArg(ctx, args, c.funcName)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -6513,12 +6515,13 @@ func (b *builtinUTCTimeWithArgSig) evalDuration(ctx EvalContext, row chunk.Row)
if isNull || err != nil {
return types.Duration{}, isNull, err
}
if fsp > int64(types.MaxFsp) {
return types.Duration{}, true, errors.Errorf("Too-big precision %v specified for 'utc_time'. Maximum is %v", fsp, types.MaxFsp)
}
if fsp < int64(types.MinFsp) {
return types.Duration{}, true, errors.Errorf("Invalid negative %d specified, must in [0, 6]", fsp)

if fsp > math.MaxInt32 || fsp < types.MinFsp {
return types.Duration{}, true, types.ErrSyntax.GenWithStack(util.SyntaxErrorPrefix)
} else if fsp > types.MaxFsp {
return types.Duration{}, true, types.ErrTooBigPrecision.GenWithStackByArgs(fsp, "utc_time", types.MaxFsp)
}

nowTs, err := getStmtTimestamp(ctx)
if err != nil {
return types.Duration{}, true, err
Expand Down Expand Up @@ -6804,7 +6807,7 @@ func calAppropriateTime(minTime, maxTime, minSafeTime time.Time) time.Time {
}

// getFspByIntArg is used by some time functions to get the result fsp. If len(expr) == 0, then the fsp is not explicit set, use 0 as default.
func getFspByIntArg(ctx BuildContext, exps []Expression) (int, error) {
func getFspByIntArg(ctx BuildContext, exps []Expression, funcName string) (int, error) {
if len(exps) == 0 {
return 0, nil
}
Expand All @@ -6818,12 +6821,12 @@ func getFspByIntArg(ctx BuildContext, exps []Expression) (int, error) {
// If isNULL, it may be a bug of parser. Return 0 to be compatible with old version.
return 0, err
}
if fsp > int64(types.MaxFsp) {
return 0, errors.Errorf("Too-big precision %v specified for 'curtime'. Maximum is %v", fsp, types.MaxFsp)
} else if fsp < int64(types.MinFsp) {
return 0, errors.Errorf("Invalid negative %d specified, must in [0, 6]", fsp)

if fsp > math.MaxInt32 || fsp < types.MinFsp {
return 0, types.ErrSyntax.GenWithStack(util.SyntaxErrorPrefix)
} else if fsp > types.MaxFsp {
return 0, types.ErrTooBigPrecision.GenWithStackByArgs(fsp, funcName, types.MaxFsp)
}
return int(fsp), nil
}
// Should no happen. But our tests may generate non-constant input.
return 0, nil
Expand Down
30 changes: 15 additions & 15 deletions pkg/expression/builtin_time_vec.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ import (
"strings"
"time"

"github.com/pingcap/errors"
"github.com/pingcap/tidb/pkg/parser/mysql"
"github.com/pingcap/tidb/pkg/parser/terror"
"github.com/pingcap/tidb/pkg/types"
"github.com/pingcap/tidb/pkg/util"
"github.com/pingcap/tidb/pkg/util/chunk"
"github.com/tikv/client-go/v2/oracle"
)
Expand Down Expand Up @@ -404,12 +404,12 @@ func (b *builtinUTCTimeWithArgSig) vecEvalDuration(ctx EvalContext, input *chunk
if result.IsNull(i) {
continue
}
fsp := i64s[i]
if fsp > int64(types.MaxFsp) {
return errors.Errorf("Too-big precision %v specified for 'utc_time'. Maximum is %v", fsp, types.MaxFsp)
if i64s[i] > math.MaxInt32 || i64s[i] < types.MinFsp {
return types.ErrSyntax.GenWithStack(util.SyntaxErrorPrefix)
}
if fsp < int64(types.MinFsp) {
return errors.Errorf("Invalid negative %d specified, must in [0, 6]", fsp)
fsp := i64s[i]
if fsp > types.MaxFsp {
return types.ErrTooBigPrecision.GenWithStackByArgs(fsp, "utc_time", types.MaxFsp)
}
res, _, err := types.ParseDuration(tc, utc, int(fsp))
if err != nil {
Expand Down Expand Up @@ -546,11 +546,11 @@ func (b *builtinNowWithArgSig) vecEvalTime(ctx EvalContext, input *chunk.Chunk,
for i := 0; i < n; i++ {
fsp := 0
if !bufFsp.IsNull(i) {
if fsps[i] > int64(types.MaxFsp) {
return errors.Errorf("Too-big precision %v specified for 'now'. Maximum is %v", fsps[i], types.MaxFsp)
if fsps[i] > math.MaxInt32 || fsps[i] < types.MinFsp {
return types.ErrSyntax.GenWithStack(util.SyntaxErrorPrefix)
}
if fsps[i] < int64(types.MinFsp) {
return errors.Errorf("Invalid negative %d specified, must in [0, 6]", fsps[i])
if fsps[i] > types.MaxFsp {
return types.ErrTooBigPrecision.GenWithStackByArgs(fsps[i], "now", types.MaxFsp)
}
fsp = int(fsps[i])
}
Expand Down Expand Up @@ -1407,12 +1407,12 @@ func (b *builtinUTCTimestampWithArgSig) vecEvalTime(ctx EvalContext, input *chun
if result.IsNull(i) {
continue
}
fsp := i64s[i]
if fsp > int64(types.MaxFsp) {
return errors.Errorf("Too-big precision %v specified for 'utc_timestamp'. Maximum is %v", fsp, types.MaxFsp)
if i64s[i] > math.MaxInt32 || i64s[i] < types.MinFsp {
return types.ErrSyntax.GenWithStack(util.SyntaxErrorPrefix)
}
if fsp < int64(types.MinFsp) {
return errors.Errorf("Invalid negative %d specified, must in [0, 6]", fsp)
fsp := i64s[i]
if fsp > types.MaxFsp {
return types.ErrTooBigPrecision.GenWithStackByArgs(fsp, "utc_timestamp", types.MaxFsp)
}
res, isNull, err := evalUTCTimestampWithFsp(ctx, int(fsp))
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/parser/mysql/errname.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ var MySQLErrName = map[uint16]*ErrMessage{
ErrNoDefaultForViewField: Message("Field of view '%-.192s.%-.192s' underlying table doesn't have a default value", nil),
ErrSpNoRecursion: Message("Recursive stored functions and triggers are not allowed.", nil),
ErrTooBigScale: Message("Too big scale %d specified for column '%-.192s'. Maximum is %d.", nil),
ErrTooBigPrecision: Message("Too big precision %d specified for column '%-.192s'. Maximum is %d.", nil),
ErrTooBigPrecision: Message("Too-big precision %d specified for '%-.192s'. Maximum is %d.", nil),
ErrMBiggerThanD: Message("For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.192s').", nil),
ErrWrongLockOfSystemTable: Message("You can't combine write-locking of system tables with other tables or lock types", nil),
ErrConnectToForeignDataSource: Message("Unable to connect to foreign data source: %.64s", nil),
Expand Down
8 changes: 4 additions & 4 deletions pkg/util/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ func HasCancelled(ctx context.Context) (cancel bool) {
}

const (
// syntaxErrorPrefix is the common prefix for SQL syntax error in TiDB.
syntaxErrorPrefix = "You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use"
// SyntaxErrorPrefix is the common prefix for SQL syntax error in TiDB.
SyntaxErrorPrefix = "You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use"
)

// SyntaxError converts parser error to TiDB's syntax error.
Expand All @@ -159,7 +159,7 @@ func SyntaxError(err error) error {
}
}

return parser.ErrParse.GenWithStackByArgs(syntaxErrorPrefix, err.Error())
return parser.ErrParse.GenWithStackByArgs(SyntaxErrorPrefix, err.Error())
}

// SyntaxWarn converts parser warn to TiDB's syntax warn.
Expand All @@ -175,7 +175,7 @@ func SyntaxWarn(err error) error {
return err
}

return parser.ErrParse.FastGenByArgs(syntaxErrorPrefix, err.Error())
return parser.ErrParse.FastGenByArgs(SyntaxErrorPrefix, err.Error())
}

var (
Expand Down
56 changes: 55 additions & 1 deletion tests/integrationtest/r/expression/builtin.result
Original file line number Diff line number Diff line change
Expand Up @@ -1181,7 +1181,7 @@ Error 1264 (22003): Out of range value for column 'a' at row 1
select cast(12.1 as decimal(3, 4));
Error 1427 (42000): For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '12.1').
SELECT CAST(1 AS DATETIME(7));
Error 1426 (42000): Too big precision 7 specified for column 'CAST'. Maximum is 6.
Error 1426 (42000): Too-big precision 7 specified for 'CAST'. Maximum is 6.
select unhex('4D7953514C');
unhex('4D7953514C')
MySQL
Expand Down Expand Up @@ -3339,3 +3339,57 @@ b
SELECT MID('abc',2);
MID('abc',2)
bc
SELECT CURRENT_TIME(-1);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use line 1 column 21 near "-1);"
SELECT CURRENT_TIME(2147483647);
Error 1426 (42000): Too-big precision 2147483647 specified for 'current_time'. Maximum is 6.
SELECT CURRENT_TIME(2147483648);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use
SELECT CURRENT_TIMESTAMP(-1);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use line 1 column 26 near "-1);"
SELECT CURRENT_TIMESTAMP(2147483647);
Error 1426 (42000): Too-big precision 2147483647 specified for 'current_timestamp'. Maximum is 6.
SELECT CURRENT_TIMESTAMP(2147483648);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use
SELECT CURTIME(-1);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use line 1 column 16 near "-1);"
SELECT CURTIME(2147483647);
Error 1426 (42000): Too-big precision 2147483647 specified for 'curtime'. Maximum is 6.
SELECT CURTIME(2147483648);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use
SELECT LOCALTIME(-1);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use line 1 column 18 near "-1);"
SELECT LOCALTIME(2147483647);
Error 1426 (42000): Too-big precision 2147483647 specified for 'localtime'. Maximum is 6.
SELECT LOCALTIME(2147483648);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use
SELECT LOCALTIMESTAMP(-1);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use line 1 column 23 near "-1);"
SELECT LOCALTIMESTAMP(2147483647);
Error 1426 (42000): Too-big precision 2147483647 specified for 'localtimestamp'. Maximum is 6.
SELECT LOCALTIMESTAMP(2147483648);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use
SELECT NOW(-1);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use
SELECT NOW(2147483647);
Error 1426 (42000): Too-big precision 2147483647 specified for 'now'. Maximum is 6.
SELECT NOW(2147483648);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use
SELECT SYSDATE(-1);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use line 1 column 16 near "-1);"
SELECT SYSDATE(2147483647);
Error 1426 (42000): Too-big precision 2147483647 specified for 'sysdate'. Maximum is 6.
SELECT SYSDATE(2147483648);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use
SELECT UTC_TIME(-1);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use line 1 column 17 near "-1);"
SELECT UTC_TIME(2147483647);
Error 1426 (42000): Too-big precision 2147483647 specified for 'utc_time'. Maximum is 6.
SELECT UTC_TIME(2147483648);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use
SELECT UTC_TIMESTAMP(-1);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use line 1 column 22 near "-1);"
SELECT UTC_TIMESTAMP(2147483647);
Error 1426 (42000): Too-big precision 2147483647 specified for 'utc_timestamp'. Maximum is 6.
SELECT UTC_TIMESTAMP(2147483648);
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use
10 changes: 5 additions & 5 deletions tests/integrationtest/r/expression/cast.result
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,15 @@ select cast(col1 as time), cast(col2 as time), cast(col3 as time), cast(col4 as
cast(col1 as time) cast(col2 as time) cast(col3 as time) cast(col4 as time) cast(col5 as time)
NULL NULL NULL NULL NULL
select cast(col1 as time(31)) from t where col1 is null;
Error 1426 (42000): Too big precision 31 specified for column 'CAST'. Maximum is 6.
Error 1426 (42000): Too-big precision 31 specified for 'CAST'. Maximum is 6.
select cast(col2 as time(31)) from t where col1 is null;
Error 1426 (42000): Too big precision 31 specified for column 'CAST'. Maximum is 6.
Error 1426 (42000): Too-big precision 31 specified for 'CAST'. Maximum is 6.
select cast(col3 as time(31)) from t where col1 is null;
Error 1426 (42000): Too big precision 31 specified for column 'CAST'. Maximum is 6.
Error 1426 (42000): Too-big precision 31 specified for 'CAST'. Maximum is 6.
select cast(col4 as time(31)) from t where col1 is null;
Error 1426 (42000): Too big precision 31 specified for column 'CAST'. Maximum is 6.
Error 1426 (42000): Too-big precision 31 specified for 'CAST'. Maximum is 6.
select cast(col5 as time(31)) from t where col1 is null;
Error 1426 (42000): Too big precision 31 specified for column 'CAST'. Maximum is 6.
Error 1426 (42000): Too-big precision 31 specified for 'CAST'. Maximum is 6.
drop table if exists t;
create table t(a varchar(50));
insert into t values ('2020-01-01 12:00:00.123456 +0600 PST');
Expand Down
Loading

0 comments on commit 33af583

Please sign in to comment.