Skip to content

Commit 7b8e174

Browse files
winoroszz-jason
authored andcommitted
*: add_date can return mysql.Time (#9830) (#10718)
1 parent dc4f2f1 commit 7b8e174

File tree

8 files changed

+552
-65
lines changed

8 files changed

+552
-65
lines changed

expression/builtin_time.go

Lines changed: 130 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2727,6 +2727,18 @@ func (du *baseDateArithmitical) add(ctx sessionctx.Context, date types.Time, int
27272727
return date, false, nil
27282728
}
27292729

2730+
func (du *baseDateArithmitical) addDuration(ctx sessionctx.Context, d types.Duration, interval string, unit string) (types.Duration, bool, error) {
2731+
dur, err := types.ExtractDurationValue(unit, interval)
2732+
if err != nil {
2733+
return types.ZeroDuration, true, handleInvalidTimeError(ctx, err)
2734+
}
2735+
retDur, err := d.Add(dur)
2736+
if err != nil {
2737+
return types.ZeroDuration, true, err
2738+
}
2739+
return retDur, false, nil
2740+
}
2741+
27302742
func (du *baseDateArithmitical) sub(ctx sessionctx.Context, date types.Time, interval string, unit string) (types.Time, bool, error) {
27312743
year, month, day, nano, err := types.ParseDurationValue(unit, interval)
27322744
if err := handleInvalidTimeError(ctx, err); err != nil {
@@ -2770,7 +2782,7 @@ func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
27702782
}
27712783

27722784
dateEvalTp := args[0].GetType().EvalType()
2773-
if dateEvalTp != types.ETString && dateEvalTp != types.ETInt {
2785+
if dateEvalTp != types.ETString && dateEvalTp != types.ETInt && dateEvalTp != types.ETDuration {
27742786
dateEvalTp = types.ETDatetime
27752787
}
27762788

@@ -2780,8 +2792,35 @@ func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
27802792
}
27812793

27822794
argTps := []types.EvalType{dateEvalTp, intervalEvalTp, types.ETString}
2783-
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, argTps...)
2784-
bf.tp.Flen, bf.tp.Decimal = mysql.MaxDatetimeFullWidth, types.UnspecifiedLength
2795+
var bf baseBuiltinFunc
2796+
if dateEvalTp == types.ETDuration {
2797+
unit, _, err := args[2].EvalString(ctx, chunk.Row{})
2798+
if err != nil {
2799+
return nil, err
2800+
}
2801+
internalFsp := 0
2802+
switch unit {
2803+
// If the unit has micro second, then the fsp must be the MaxFsp.
2804+
case "MICROSECOND", "SECOND_MICROSECOND", "MINUTE_MICROSECOND", "HOUR_MICROSECOND", "DAY_MICROSECOND":
2805+
internalFsp = types.MaxFsp
2806+
// If the unit is second, the fsp is related with the arg[1]'s.
2807+
case "SECOND":
2808+
internalFsp = types.MaxFsp
2809+
if intervalEvalTp != types.ETString {
2810+
internalFsp = mathutil.Min(args[1].GetType().Decimal, types.MaxFsp)
2811+
}
2812+
// Otherwise, the fsp should be 0.
2813+
}
2814+
bf = newBaseBuiltinFuncWithTp(ctx, args, types.ETDuration, argTps...)
2815+
arg0Dec, err := getExpressionFsp(ctx, args[0])
2816+
if err != nil {
2817+
return nil, err
2818+
}
2819+
bf.tp.Flen, bf.tp.Decimal = mysql.MaxDurationWidthWithFsp, mathutil.Max(arg0Dec, internalFsp)
2820+
} else {
2821+
bf = newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, argTps...)
2822+
bf.tp.Flen, bf.tp.Decimal = mysql.MaxDatetimeFullWidth, types.UnspecifiedLength
2823+
}
27852824

27862825
switch {
27872826
case dateEvalTp == types.ETString && intervalEvalTp == types.ETString:
@@ -2844,6 +2883,21 @@ func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
28442883
baseBuiltinFunc: bf,
28452884
baseDateArithmitical: newDateArighmeticalUtil(),
28462885
}
2886+
case dateEvalTp == types.ETDuration && intervalEvalTp == types.ETString:
2887+
sig = &builtinAddDateDurationStringSig{
2888+
baseBuiltinFunc: bf,
2889+
baseDateArithmitical: newDateArighmeticalUtil(),
2890+
}
2891+
case dateEvalTp == types.ETDuration && intervalEvalTp == types.ETInt:
2892+
sig = &builtinAddDateDurationIntSig{
2893+
baseBuiltinFunc: bf,
2894+
baseDateArithmitical: newDateArighmeticalUtil(),
2895+
}
2896+
case dateEvalTp == types.ETDuration && intervalEvalTp == types.ETDecimal:
2897+
sig = &builtinAddDateDurationDecimalSig{
2898+
baseBuiltinFunc: bf,
2899+
baseDateArithmitical: newDateArighmeticalUtil(),
2900+
}
28472901
}
28482902
return sig, nil
28492903
}
@@ -3244,6 +3298,79 @@ func (b *builtinAddDateDatetimeDecimalSig) evalTime(row chunk.Row) (types.Time,
32443298
return result, isNull || err != nil, errors.Trace(err)
32453299
}
32463300

3301+
type builtinAddDateDurationStringSig struct {
3302+
baseBuiltinFunc
3303+
baseDateArithmitical
3304+
}
3305+
3306+
func (b *builtinAddDateDurationStringSig) evalDuration(row chunk.Row) (types.Duration, bool, error) {
3307+
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
3308+
if isNull || err != nil {
3309+
return types.ZeroDuration, true, err
3310+
}
3311+
3312+
dur, isNull, err := b.args[0].EvalDuration(b.ctx, row)
3313+
if isNull || err != nil {
3314+
return types.ZeroDuration, true, err
3315+
}
3316+
3317+
interval, isNull, err := b.getIntervalFromString(b.ctx, b.args, row, unit)
3318+
if isNull || err != nil {
3319+
return types.ZeroDuration, true, err
3320+
}
3321+
3322+
result, isNull, err := b.addDuration(b.ctx, dur, interval, unit)
3323+
return result, isNull || err != nil, err
3324+
}
3325+
3326+
type builtinAddDateDurationIntSig struct {
3327+
baseBuiltinFunc
3328+
baseDateArithmitical
3329+
}
3330+
3331+
func (b *builtinAddDateDurationIntSig) evalDuration(row chunk.Row) (types.Duration, bool, error) {
3332+
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
3333+
if isNull || err != nil {
3334+
return types.ZeroDuration, true, err
3335+
}
3336+
3337+
dur, isNull, err := b.args[0].EvalDuration(b.ctx, row)
3338+
if isNull || err != nil {
3339+
return types.ZeroDuration, true, err
3340+
}
3341+
interval, isNull, err := b.getIntervalFromInt(b.ctx, b.args, row, unit)
3342+
if isNull || err != nil {
3343+
return types.ZeroDuration, true, err
3344+
}
3345+
3346+
result, isNull, err := b.addDuration(b.ctx, dur, interval, unit)
3347+
return result, isNull || err != nil, err
3348+
}
3349+
3350+
type builtinAddDateDurationDecimalSig struct {
3351+
baseBuiltinFunc
3352+
baseDateArithmitical
3353+
}
3354+
3355+
func (b *builtinAddDateDurationDecimalSig) evalDuration(row chunk.Row) (types.Duration, bool, error) {
3356+
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
3357+
if isNull || err != nil {
3358+
return types.ZeroDuration, true, err
3359+
}
3360+
3361+
dur, isNull, err := b.args[0].EvalDuration(b.ctx, row)
3362+
if isNull || err != nil {
3363+
return types.ZeroDuration, true, err
3364+
}
3365+
interval, isNull, err := b.getIntervalFromDecimal(b.ctx, b.args, row, unit)
3366+
if isNull || err != nil {
3367+
return types.ZeroDuration, true, err
3368+
}
3369+
3370+
result, isNull, err := b.addDuration(b.ctx, dur, interval, unit)
3371+
return result, isNull || err != nil, err
3372+
}
3373+
32473374
type subDateFunctionClass struct {
32483375
baseFunctionClass
32493376
}

expression/builtin_time_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,6 +1742,33 @@ func (s *testEvaluatorSuite) TestDateArithFuncs(c *C) {
17421742
c.Assert(err, IsNil)
17431743
c.Assert(v.GetMysqlTime().String(), Equals, test.expected)
17441744
}
1745+
testDurations := []struct {
1746+
dur string
1747+
fsp int
1748+
unit string
1749+
format interface{}
1750+
expected string
1751+
}{
1752+
{
1753+
dur: "00:00:00",
1754+
fsp: 0,
1755+
unit: "MICROSECOND",
1756+
format: "100",
1757+
expected: "00:00:00.000100",
1758+
},
1759+
}
1760+
for _, tt := range testDurations {
1761+
dur, _, ok, err := types.StrToDuration(nil, tt.dur, tt.fsp)
1762+
c.Assert(err, IsNil)
1763+
c.Assert(ok, IsTrue)
1764+
args = types.MakeDatums(dur, tt.format, tt.unit)
1765+
f, err = fcAdd.getFunction(s.ctx, s.datumsToConstants(args))
1766+
c.Assert(err, IsNil)
1767+
c.Assert(f, NotNil)
1768+
v, err = evalBuiltinFunc(f, chunk.Row{})
1769+
c.Assert(err, IsNil)
1770+
c.Assert(v.GetMysqlDuration().String(), Equals, tt.expected)
1771+
}
17451772
}
17461773

17471774
func (s *testEvaluatorSuite) TestTimestamp(c *C) {

mysql/const_test.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ package mysql_test
1515

1616
import (
1717
"flag"
18-
"testing"
1918

2019
. "github.com/pingcap/check"
2120
"github.com/pingcap/parser"
@@ -30,11 +29,6 @@ import (
3029
"golang.org/x/net/context"
3130
)
3231

33-
func TestT(t *testing.T) {
34-
CustomVerboseFlag = true
35-
TestingT(t)
36-
}
37-
3832
var _ = Suite(&testMySQLConstSuite{})
3933

4034
type testMySQLConstSuite struct {

types/errors.go

Lines changed: 53 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package types
1515

1616
import (
17+
"github.com/pingcap/errors"
1718
"github.com/pingcap/parser/mysql"
1819
"github.com/pingcap/parser/terror"
1920
parser_types "github.com/pingcap/parser/types"
@@ -57,27 +58,45 @@ var (
5758
// ErrWarnDataOutOfRange is returned when the value in a numeric column that is outside the permissible range of the column data type.
5859
// See https://dev.mysql.com/doc/refman/5.5/en/out-of-range-and-overflow.html for details
5960
ErrWarnDataOutOfRange = terror.ClassTypes.New(codeDataOutOfRange, mysql.MySQLErrName[mysql.ErrWarnDataOutOfRange])
61+
// ErrDuplicatedValueInType is returned when enum column has duplicated value.
62+
ErrDuplicatedValueInType = terror.ClassTypes.New(codeDuplicatedValueInType, mysql.MySQLErrName[mysql.ErrDuplicatedValueInType])
63+
// ErrDatetimeFunctionOverflow is returned when the calculation in datetime function cause overflow.
64+
ErrDatetimeFunctionOverflow = terror.ClassTypes.New(codeDatetimeFunctionOverflow, mysql.MySQLErrName[mysql.ErrDatetimeFunctionOverflow])
65+
// ErrInvalidTimeFormat is returned when the time format is not correct.
66+
ErrInvalidTimeFormat = terror.ClassTypes.New(mysql.ErrTruncatedWrongValue, "invalid time format: '%v'")
67+
// ErrInvalidWeekModeFormat is returned when the week mode is wrong.
68+
ErrInvalidWeekModeFormat = terror.ClassTypes.New(mysql.ErrTruncatedWrongValue, "invalid week mode format: '%v'")
69+
// ErrInvalidYearFormat is returned when the input is not a valid year format.
70+
ErrInvalidYearFormat = errors.New("invalid year format")
71+
// ErrInvalidYear is returned when the input value is not a valid year.
72+
ErrInvalidYear = errors.New("invalid year")
73+
// ErrIncorrectDatetimeValue is returned when the input is not valid date time value.
74+
ErrIncorrectDatetimeValue = terror.ClassTypes.New(mysql.ErrTruncatedWrongValue, "Incorrect datetime value: '%s'")
75+
// ErrTruncatedWrongValue is returned then
76+
ErrTruncatedWrongValue = terror.ClassTypes.New(mysql.ErrTruncatedWrongValue, mysql.MySQLErrName[mysql.ErrTruncatedWrongValue])
6077
)
6178

6279
const (
6380
codeBadNumber terror.ErrCode = 1
6481

65-
codeDataTooLong = terror.ErrCode(mysql.ErrDataTooLong)
66-
codeIllegalValueForType = terror.ErrCode(mysql.ErrIllegalValueForType)
67-
codeTruncated = terror.ErrCode(mysql.WarnDataTruncated)
68-
codeOverflow = terror.ErrCode(mysql.ErrDataOutOfRange)
69-
codeDivByZero = terror.ErrCode(mysql.ErrDivisionByZero)
70-
codeTooBigDisplayWidth = terror.ErrCode(mysql.ErrTooBigDisplaywidth)
71-
codeTooBigFieldLength = terror.ErrCode(mysql.ErrTooBigFieldlength)
72-
codeTooBigSet = terror.ErrCode(mysql.ErrTooBigSet)
73-
codeTooBigScale = terror.ErrCode(mysql.ErrTooBigScale)
74-
codeTooBigPrecision = terror.ErrCode(mysql.ErrTooBigPrecision)
75-
codeWrongFieldSpec = terror.ErrCode(mysql.ErrWrongFieldSpec)
76-
codeTruncatedWrongValue = terror.ErrCode(mysql.ErrTruncatedWrongValue)
77-
codeUnknown = terror.ErrCode(mysql.ErrUnknown)
78-
codeInvalidDefault = terror.ErrCode(mysql.ErrInvalidDefault)
79-
codeMBiggerThanD = terror.ErrCode(mysql.ErrMBiggerThanD)
80-
codeDataOutOfRange = terror.ErrCode(mysql.ErrWarnDataOutOfRange)
82+
codeDataTooLong = terror.ErrCode(mysql.ErrDataTooLong)
83+
codeIllegalValueForType = terror.ErrCode(mysql.ErrIllegalValueForType)
84+
codeTruncated = terror.ErrCode(mysql.WarnDataTruncated)
85+
codeOverflow = terror.ErrCode(mysql.ErrDataOutOfRange)
86+
codeDivByZero = terror.ErrCode(mysql.ErrDivisionByZero)
87+
codeTooBigDisplayWidth = terror.ErrCode(mysql.ErrTooBigDisplaywidth)
88+
codeTooBigFieldLength = terror.ErrCode(mysql.ErrTooBigFieldlength)
89+
codeTooBigSet = terror.ErrCode(mysql.ErrTooBigSet)
90+
codeTooBigScale = terror.ErrCode(mysql.ErrTooBigScale)
91+
codeTooBigPrecision = terror.ErrCode(mysql.ErrTooBigPrecision)
92+
codeWrongFieldSpec = terror.ErrCode(mysql.ErrWrongFieldSpec)
93+
codeTruncatedWrongValue = terror.ErrCode(mysql.ErrTruncatedWrongValue)
94+
codeUnknown = terror.ErrCode(mysql.ErrUnknown)
95+
codeInvalidDefault = terror.ErrCode(mysql.ErrInvalidDefault)
96+
codeMBiggerThanD = terror.ErrCode(mysql.ErrMBiggerThanD)
97+
codeDataOutOfRange = terror.ErrCode(mysql.ErrWarnDataOutOfRange)
98+
codeDuplicatedValueInType = terror.ErrCode(mysql.ErrDuplicatedValueInType)
99+
codeDatetimeFunctionOverflow = terror.ErrCode(mysql.ErrDatetimeFunctionOverflow)
81100
)
82101

83102
var (
@@ -89,22 +108,24 @@ var (
89108

90109
func init() {
91110
typesMySQLErrCodes := map[terror.ErrCode]uint16{
92-
codeDataTooLong: mysql.ErrDataTooLong,
93-
codeIllegalValueForType: mysql.ErrIllegalValueForType,
94-
codeTruncated: mysql.WarnDataTruncated,
95-
codeOverflow: mysql.ErrDataOutOfRange,
96-
codeDivByZero: mysql.ErrDivisionByZero,
97-
codeTooBigDisplayWidth: mysql.ErrTooBigDisplaywidth,
98-
codeTooBigFieldLength: mysql.ErrTooBigFieldlength,
99-
codeTooBigSet: mysql.ErrTooBigSet,
100-
codeTooBigScale: mysql.ErrTooBigScale,
101-
codeTooBigPrecision: mysql.ErrTooBigPrecision,
102-
codeWrongFieldSpec: mysql.ErrWrongFieldSpec,
103-
codeTruncatedWrongValue: mysql.ErrTruncatedWrongValue,
104-
codeUnknown: mysql.ErrUnknown,
105-
codeInvalidDefault: mysql.ErrInvalidDefault,
106-
codeMBiggerThanD: mysql.ErrMBiggerThanD,
107-
codeDataOutOfRange: mysql.ErrWarnDataOutOfRange,
111+
codeDataTooLong: mysql.ErrDataTooLong,
112+
codeIllegalValueForType: mysql.ErrIllegalValueForType,
113+
codeTruncated: mysql.WarnDataTruncated,
114+
codeOverflow: mysql.ErrDataOutOfRange,
115+
codeDivByZero: mysql.ErrDivisionByZero,
116+
codeTooBigDisplayWidth: mysql.ErrTooBigDisplaywidth,
117+
codeTooBigFieldLength: mysql.ErrTooBigFieldlength,
118+
codeTooBigSet: mysql.ErrTooBigSet,
119+
codeTooBigScale: mysql.ErrTooBigScale,
120+
codeTooBigPrecision: mysql.ErrTooBigPrecision,
121+
codeWrongFieldSpec: mysql.ErrWrongFieldSpec,
122+
codeTruncatedWrongValue: mysql.ErrTruncatedWrongValue,
123+
codeUnknown: mysql.ErrUnknown,
124+
codeInvalidDefault: mysql.ErrInvalidDefault,
125+
codeMBiggerThanD: mysql.ErrMBiggerThanD,
126+
codeDataOutOfRange: mysql.ErrWarnDataOutOfRange,
127+
codeDuplicatedValueInType: mysql.ErrDuplicatedValueInType,
128+
codeDatetimeFunctionOverflow: mysql.ErrDatetimeFunctionOverflow,
108129
}
109130
terror.ErrClassToMySQLCodes[terror.ClassTypes] = typesMySQLErrCodes
110131
}

0 commit comments

Comments
 (0)