Skip to content

Commit 9909e04

Browse files
committed
Support add datetime with real interval (pingcap#10347)
1 parent d22ecd0 commit 9909e04

File tree

2 files changed

+266
-2
lines changed

2 files changed

+266
-2
lines changed

expression/builtin_time.go

Lines changed: 244 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,21 +216,27 @@ var (
216216
_ builtinFunc = &builtinExtractDurationSig{}
217217
_ builtinFunc = &builtinAddDateStringStringSig{}
218218
_ builtinFunc = &builtinAddDateStringIntSig{}
219+
_ builtinFunc = &builtinAddDateStringRealSig{}
219220
_ builtinFunc = &builtinAddDateStringDecimalSig{}
220221
_ builtinFunc = &builtinAddDateIntStringSig{}
221222
_ builtinFunc = &builtinAddDateIntIntSig{}
223+
_ builtinFunc = &builtinAddDateIntRealSig{}
222224
_ builtinFunc = &builtinAddDateIntDecimalSig{}
223225
_ builtinFunc = &builtinAddDateDatetimeStringSig{}
224226
_ builtinFunc = &builtinAddDateDatetimeIntSig{}
227+
_ builtinFunc = &builtinAddDateDatetimeRealSig{}
225228
_ builtinFunc = &builtinAddDateDatetimeDecimalSig{}
226229
_ builtinFunc = &builtinSubDateStringStringSig{}
227230
_ builtinFunc = &builtinSubDateStringIntSig{}
231+
_ builtinFunc = &builtinSubDateStringRealSig{}
228232
_ builtinFunc = &builtinSubDateStringDecimalSig{}
229233
_ builtinFunc = &builtinSubDateIntStringSig{}
230234
_ builtinFunc = &builtinSubDateIntIntSig{}
235+
_ builtinFunc = &builtinSubDateIntRealSig{}
231236
_ builtinFunc = &builtinSubDateIntDecimalSig{}
232237
_ builtinFunc = &builtinSubDateDatetimeStringSig{}
233238
_ builtinFunc = &builtinSubDateDatetimeIntSig{}
239+
_ builtinFunc = &builtinSubDateDatetimeRealSig{}
234240
_ builtinFunc = &builtinSubDateDatetimeDecimalSig{}
235241
)
236242

@@ -2631,6 +2637,14 @@ func (du *baseDateArithmitical) getIntervalFromInt(ctx sessionctx.Context, args
26312637
return strconv.FormatInt(interval, 10), false, nil
26322638
}
26332639

2640+
func (du *baseDateArithmitical) getIntervalFromReal(ctx sessionctx.Context, args []Expression, row chunk.Row, unit string) (string, bool, error) {
2641+
interval, isNull, err := args[1].EvalReal(ctx, row)
2642+
if isNull || err != nil {
2643+
return "", true, err
2644+
}
2645+
return strconv.FormatFloat(interval, 'f', -1, 64), false, nil
2646+
}
2647+
26342648
func (du *baseDateArithmitical) add(ctx sessionctx.Context, date types.Time, interval string, unit string) (types.Time, bool, error) {
26352649
year, month, day, dur, err := types.ExtractTimeValue(unit, interval)
26362650
if err != nil {
@@ -2711,7 +2725,7 @@ func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
27112725
}
27122726

27132727
intervalEvalTp := args[1].GetType().EvalType()
2714-
if intervalEvalTp != types.ETString && intervalEvalTp != types.ETDecimal {
2728+
if intervalEvalTp != types.ETString && intervalEvalTp != types.ETDecimal && intervalEvalTp != types.ETReal {
27152729
intervalEvalTp = types.ETInt
27162730
}
27172731

@@ -2730,6 +2744,11 @@ func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
27302744
baseBuiltinFunc: bf,
27312745
baseDateArithmitical: newDateArighmeticalUtil(),
27322746
}
2747+
case dateEvalTp == types.ETString && intervalEvalTp == types.ETReal:
2748+
sig = &builtinAddDateStringRealSig{
2749+
baseBuiltinFunc: bf,
2750+
baseDateArithmitical: newDateArighmeticalUtil(),
2751+
}
27332752
case dateEvalTp == types.ETString && intervalEvalTp == types.ETDecimal:
27342753
sig = &builtinAddDateStringDecimalSig{
27352754
baseBuiltinFunc: bf,
@@ -2745,6 +2764,11 @@ func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
27452764
baseBuiltinFunc: bf,
27462765
baseDateArithmitical: newDateArighmeticalUtil(),
27472766
}
2767+
case dateEvalTp == types.ETInt && intervalEvalTp == types.ETReal:
2768+
sig = &builtinAddDateIntRealSig{
2769+
baseBuiltinFunc: bf,
2770+
baseDateArithmitical: newDateArighmeticalUtil(),
2771+
}
27482772
case dateEvalTp == types.ETInt && intervalEvalTp == types.ETDecimal:
27492773
sig = &builtinAddDateIntDecimalSig{
27502774
baseBuiltinFunc: bf,
@@ -2760,6 +2784,11 @@ func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
27602784
baseBuiltinFunc: bf,
27612785
baseDateArithmitical: newDateArighmeticalUtil(),
27622786
}
2787+
case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETReal:
2788+
sig = &builtinAddDateDatetimeRealSig{
2789+
baseBuiltinFunc: bf,
2790+
baseDateArithmitical: newDateArighmeticalUtil(),
2791+
}
27632792
case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETDecimal:
27642793
sig = &builtinAddDateDatetimeDecimalSig{
27652794
baseBuiltinFunc: bf,
@@ -2835,6 +2864,39 @@ func (b *builtinAddDateStringIntSig) evalTime(row chunk.Row) (types.Time, bool,
28352864
return result, isNull || err != nil, errors.Trace(err)
28362865
}
28372866

2867+
type builtinAddDateStringRealSig struct {
2868+
baseBuiltinFunc
2869+
baseDateArithmitical
2870+
}
2871+
2872+
func (b *builtinAddDateStringRealSig) Clone() builtinFunc {
2873+
newSig := &builtinAddDateStringRealSig{baseDateArithmitical: b.baseDateArithmitical}
2874+
newSig.cloneFrom(&b.baseBuiltinFunc)
2875+
return newSig
2876+
}
2877+
2878+
// evalTime evals ADDDATE(date,INTERVAL expr unit).
2879+
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_adddate
2880+
func (b *builtinAddDateStringRealSig) evalTime(row chunk.Row) (types.Time, bool, error) {
2881+
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
2882+
if isNull || err != nil {
2883+
return types.Time{}, true, err
2884+
}
2885+
2886+
date, isNull, err := b.getDateFromString(b.ctx, b.args, row, unit)
2887+
if isNull || err != nil {
2888+
return types.Time{}, true, err
2889+
}
2890+
2891+
interval, isNull, err := b.getIntervalFromReal(b.ctx, b.args, row, unit)
2892+
if isNull || err != nil {
2893+
return types.Time{}, true, err
2894+
}
2895+
2896+
result, isNull, err := b.add(b.ctx, date, interval, unit)
2897+
return result, isNull || err != nil, err
2898+
}
2899+
28382900
type builtinAddDateStringDecimalSig struct {
28392901
baseBuiltinFunc
28402902
baseDateArithmitical
@@ -2934,6 +2996,39 @@ func (b *builtinAddDateIntIntSig) evalTime(row chunk.Row) (types.Time, bool, err
29342996
return result, isNull || err != nil, errors.Trace(err)
29352997
}
29362998

2999+
type builtinAddDateIntRealSig struct {
3000+
baseBuiltinFunc
3001+
baseDateArithmitical
3002+
}
3003+
3004+
func (b *builtinAddDateIntRealSig) Clone() builtinFunc {
3005+
newSig := &builtinAddDateIntRealSig{baseDateArithmitical: b.baseDateArithmitical}
3006+
newSig.cloneFrom(&b.baseBuiltinFunc)
3007+
return newSig
3008+
}
3009+
3010+
// evalTime evals ADDDATE(date,INTERVAL expr unit).
3011+
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_adddate
3012+
func (b *builtinAddDateIntRealSig) evalTime(row chunk.Row) (types.Time, bool, error) {
3013+
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
3014+
if isNull || err != nil {
3015+
return types.Time{}, true, err
3016+
}
3017+
3018+
date, isNull, err := b.getDateFromInt(b.ctx, b.args, row, unit)
3019+
if isNull || err != nil {
3020+
return types.Time{}, true, err
3021+
}
3022+
3023+
interval, isNull, err := b.getIntervalFromReal(b.ctx, b.args, row, unit)
3024+
if isNull || err != nil {
3025+
return types.Time{}, true, err
3026+
}
3027+
3028+
result, isNull, err := b.add(b.ctx, date, interval, unit)
3029+
return result, isNull || err != nil, err
3030+
}
3031+
29373032
type builtinAddDateIntDecimalSig struct {
29383033
baseBuiltinFunc
29393034
baseDateArithmitical
@@ -3033,6 +3128,39 @@ func (b *builtinAddDateDatetimeIntSig) evalTime(row chunk.Row) (types.Time, bool
30333128
return result, isNull || err != nil, errors.Trace(err)
30343129
}
30353130

3131+
type builtinAddDateDatetimeRealSig struct {
3132+
baseBuiltinFunc
3133+
baseDateArithmitical
3134+
}
3135+
3136+
func (b *builtinAddDateDatetimeRealSig) Clone() builtinFunc {
3137+
newSig := &builtinAddDateDatetimeRealSig{baseDateArithmitical: b.baseDateArithmitical}
3138+
newSig.cloneFrom(&b.baseBuiltinFunc)
3139+
return newSig
3140+
}
3141+
3142+
// evalTime evals ADDDATE(date,INTERVAL expr unit).
3143+
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_adddate
3144+
func (b *builtinAddDateDatetimeRealSig) evalTime(row chunk.Row) (types.Time, bool, error) {
3145+
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
3146+
if isNull || err != nil {
3147+
return types.Time{}, true, err
3148+
}
3149+
3150+
date, isNull, err := b.getDateFromDatetime(b.ctx, b.args, row, unit)
3151+
if isNull || err != nil {
3152+
return types.Time{}, true, err
3153+
}
3154+
3155+
interval, isNull, err := b.getIntervalFromReal(b.ctx, b.args, row, unit)
3156+
if isNull || err != nil {
3157+
return types.Time{}, true, err
3158+
}
3159+
3160+
result, isNull, err := b.add(b.ctx, date, interval, unit)
3161+
return result, isNull || err != nil, err
3162+
}
3163+
30363164
type builtinAddDateDatetimeDecimalSig struct {
30373165
baseBuiltinFunc
30383166
baseDateArithmitical
@@ -3081,7 +3209,7 @@ func (c *subDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
30813209
}
30823210

30833211
intervalEvalTp := args[1].GetType().EvalType()
3084-
if intervalEvalTp != types.ETString && intervalEvalTp != types.ETDecimal {
3212+
if intervalEvalTp != types.ETString && intervalEvalTp != types.ETDecimal && intervalEvalTp != types.ETReal {
30853213
intervalEvalTp = types.ETInt
30863214
}
30873215

@@ -3100,6 +3228,11 @@ func (c *subDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
31003228
baseBuiltinFunc: bf,
31013229
baseDateArithmitical: newDateArighmeticalUtil(),
31023230
}
3231+
case dateEvalTp == types.ETString && intervalEvalTp == types.ETReal:
3232+
sig = &builtinSubDateStringRealSig{
3233+
baseBuiltinFunc: bf,
3234+
baseDateArithmitical: newDateArighmeticalUtil(),
3235+
}
31033236
case dateEvalTp == types.ETString && intervalEvalTp == types.ETDecimal:
31043237
sig = &builtinSubDateStringDecimalSig{
31053238
baseBuiltinFunc: bf,
@@ -3115,6 +3248,11 @@ func (c *subDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
31153248
baseBuiltinFunc: bf,
31163249
baseDateArithmitical: newDateArighmeticalUtil(),
31173250
}
3251+
case dateEvalTp == types.ETInt && intervalEvalTp == types.ETReal:
3252+
sig = &builtinSubDateIntRealSig{
3253+
baseBuiltinFunc: bf,
3254+
baseDateArithmitical: newDateArighmeticalUtil(),
3255+
}
31183256
case dateEvalTp == types.ETInt && intervalEvalTp == types.ETDecimal:
31193257
sig = &builtinSubDateIntDecimalSig{
31203258
baseBuiltinFunc: bf,
@@ -3130,6 +3268,11 @@ func (c *subDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
31303268
baseBuiltinFunc: bf,
31313269
baseDateArithmitical: newDateArighmeticalUtil(),
31323270
}
3271+
case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETReal:
3272+
sig = &builtinSubDateDatetimeRealSig{
3273+
baseBuiltinFunc: bf,
3274+
baseDateArithmitical: newDateArighmeticalUtil(),
3275+
}
31333276
case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETDecimal:
31343277
sig = &builtinSubDateDatetimeDecimalSig{
31353278
baseBuiltinFunc: bf,
@@ -3205,6 +3348,39 @@ func (b *builtinSubDateStringIntSig) evalTime(row chunk.Row) (types.Time, bool,
32053348
return result, isNull || err != nil, errors.Trace(err)
32063349
}
32073350

3351+
type builtinSubDateStringRealSig struct {
3352+
baseBuiltinFunc
3353+
baseDateArithmitical
3354+
}
3355+
3356+
func (b *builtinSubDateStringRealSig) Clone() builtinFunc {
3357+
newSig := &builtinSubDateStringRealSig{baseDateArithmitical: b.baseDateArithmitical}
3358+
newSig.cloneFrom(&b.baseBuiltinFunc)
3359+
return newSig
3360+
}
3361+
3362+
// evalTime evals SUBDATE(date,INTERVAL expr unit).
3363+
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subdate
3364+
func (b *builtinSubDateStringRealSig) evalTime(row chunk.Row) (types.Time, bool, error) {
3365+
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
3366+
if isNull || err != nil {
3367+
return types.Time{}, true, err
3368+
}
3369+
3370+
date, isNull, err := b.getDateFromString(b.ctx, b.args, row, unit)
3371+
if isNull || err != nil {
3372+
return types.Time{}, true, err
3373+
}
3374+
3375+
interval, isNull, err := b.getIntervalFromReal(b.ctx, b.args, row, unit)
3376+
if isNull || err != nil {
3377+
return types.Time{}, true, err
3378+
}
3379+
3380+
result, isNull, err := b.sub(b.ctx, date, interval, unit)
3381+
return result, isNull || err != nil, err
3382+
}
3383+
32083384
type builtinSubDateStringDecimalSig struct {
32093385
baseBuiltinFunc
32103386
baseDateArithmitical
@@ -3302,6 +3478,39 @@ func (b *builtinSubDateIntIntSig) evalTime(row chunk.Row) (types.Time, bool, err
33023478
return result, isNull || err != nil, errors.Trace(err)
33033479
}
33043480

3481+
type builtinSubDateIntRealSig struct {
3482+
baseBuiltinFunc
3483+
baseDateArithmitical
3484+
}
3485+
3486+
func (b *builtinSubDateIntRealSig) Clone() builtinFunc {
3487+
newSig := &builtinSubDateIntRealSig{baseDateArithmitical: b.baseDateArithmitical}
3488+
newSig.cloneFrom(&b.baseBuiltinFunc)
3489+
return newSig
3490+
}
3491+
3492+
// evalTime evals SUBDATE(date,INTERVAL expr unit).
3493+
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subdate
3494+
func (b *builtinSubDateIntRealSig) evalTime(row chunk.Row) (types.Time, bool, error) {
3495+
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
3496+
if isNull || err != nil {
3497+
return types.Time{}, true, err
3498+
}
3499+
3500+
date, isNull, err := b.getDateFromInt(b.ctx, b.args, row, unit)
3501+
if isNull || err != nil {
3502+
return types.Time{}, true, err
3503+
}
3504+
3505+
interval, isNull, err := b.getIntervalFromReal(b.ctx, b.args, row, unit)
3506+
if isNull || err != nil {
3507+
return types.Time{}, true, err
3508+
}
3509+
3510+
result, isNull, err := b.sub(b.ctx, date, interval, unit)
3511+
return result, isNull || err != nil, err
3512+
}
3513+
33053514
type builtinSubDateDatetimeStringSig struct {
33063515
baseBuiltinFunc
33073516
baseDateArithmitical
@@ -3401,6 +3610,39 @@ func (b *builtinSubDateDatetimeIntSig) evalTime(row chunk.Row) (types.Time, bool
34013610
return result, isNull || err != nil, errors.Trace(err)
34023611
}
34033612

3613+
type builtinSubDateDatetimeRealSig struct {
3614+
baseBuiltinFunc
3615+
baseDateArithmitical
3616+
}
3617+
3618+
func (b *builtinSubDateDatetimeRealSig) Clone() builtinFunc {
3619+
newSig := &builtinSubDateDatetimeRealSig{baseDateArithmitical: b.baseDateArithmitical}
3620+
newSig.cloneFrom(&b.baseBuiltinFunc)
3621+
return newSig
3622+
}
3623+
3624+
// evalTime evals SUBDATE(date,INTERVAL expr unit).
3625+
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subdate
3626+
func (b *builtinSubDateDatetimeRealSig) evalTime(row chunk.Row) (types.Time, bool, error) {
3627+
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
3628+
if isNull || err != nil {
3629+
return types.Time{}, true, err
3630+
}
3631+
3632+
date, isNull, err := b.getDateFromDatetime(b.ctx, b.args, row, unit)
3633+
if isNull || err != nil {
3634+
return types.Time{}, true, err
3635+
}
3636+
3637+
interval, isNull, err := b.getIntervalFromReal(b.ctx, b.args, row, unit)
3638+
if isNull || err != nil {
3639+
return types.Time{}, true, err
3640+
}
3641+
3642+
result, isNull, err := b.sub(b.ctx, date, interval, unit)
3643+
return result, isNull || err != nil, err
3644+
}
3645+
34043646
type builtinSubDateDatetimeDecimalSig struct {
34053647
baseBuiltinFunc
34063648
baseDateArithmitical

expression/integration_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3908,3 +3908,25 @@ func (s *testIntegrationSuite) TestTimestampDatumEncode(c *C) {
39083908
))
39093909
tk.MustQuery(`select * from t where b = (select max(b) from t)`).Check(testkit.Rows(`1 2019-04-29 11:56:12`))
39103910
}
3911+
3912+
func (s *testIntegrationSuite) TestDateTimeAddReal(c *C) {
3913+
tk := testkit.NewTestKit(c, s.store)
3914+
defer s.cleanEnv(c)
3915+
3916+
cases := []struct {
3917+
sql string
3918+
result string
3919+
}{
3920+
{`SELECT "1900-01-01 00:00:00" + INTERVAL 1.123456789e3 SECOND;`, "1900-01-01 00:18:43.456789"},
3921+
{`SELECT 19000101000000 + INTERVAL 1.123456789e3 SECOND;`, "1900-01-01 00:18:43.456789"},
3922+
{`select date("1900-01-01") + interval 1.123456789e3 second;`, "1900-01-01 00:18:43.456789"},
3923+
{`SELECT "1900-01-01 00:18:43.456789" - INTERVAL 1.123456789e3 SECOND;`, "1900-01-01 00:00:00"},
3924+
{`SELECT 19000101001843.456789 - INTERVAL 1.123456789e3 SECOND;`, "1900-01-01 00:00:00"},
3925+
{`select date("1900-01-01") - interval 1.123456789e3 second;`, "1899-12-31 23:41:16.543211"},
3926+
{`select 19000101000000 - interval 1.123456789e3 second;`, "1899-12-31 23:41:16.543211"},
3927+
}
3928+
3929+
for _, c := range cases {
3930+
tk.MustQuery(c.sql).Check(testkit.Rows(c.result))
3931+
}
3932+
}

0 commit comments

Comments
 (0)