Skip to content

Commit 26d05fa

Browse files
erjiaqingzz-jason
authored andcommitted
Support add datetime with real interval (#10347) (#10418)
1 parent 7370996 commit 26d05fa

File tree

2 files changed

+266
-2
lines changed

2 files changed

+266
-2
lines changed

expression/builtin_time.go

+244-2
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, nano, err := types.ParseDurationValue(unit, interval)
26362650
if err := handleInvalidTimeError(ctx, err); err != nil {
@@ -2710,7 +2724,7 @@ func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
27102724
}
27112725

27122726
intervalEvalTp := args[1].GetType().EvalType()
2713-
if intervalEvalTp != types.ETString && intervalEvalTp != types.ETDecimal {
2727+
if intervalEvalTp != types.ETString && intervalEvalTp != types.ETDecimal && intervalEvalTp != types.ETReal {
27142728
intervalEvalTp = types.ETInt
27152729
}
27162730

@@ -2729,6 +2743,11 @@ func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
27292743
baseBuiltinFunc: bf,
27302744
baseDateArithmitical: newDateArighmeticalUtil(),
27312745
}
2746+
case dateEvalTp == types.ETString && intervalEvalTp == types.ETReal:
2747+
sig = &builtinAddDateStringRealSig{
2748+
baseBuiltinFunc: bf,
2749+
baseDateArithmitical: newDateArighmeticalUtil(),
2750+
}
27322751
case dateEvalTp == types.ETString && intervalEvalTp == types.ETDecimal:
27332752
sig = &builtinAddDateStringDecimalSig{
27342753
baseBuiltinFunc: bf,
@@ -2744,6 +2763,11 @@ func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
27442763
baseBuiltinFunc: bf,
27452764
baseDateArithmitical: newDateArighmeticalUtil(),
27462765
}
2766+
case dateEvalTp == types.ETInt && intervalEvalTp == types.ETReal:
2767+
sig = &builtinAddDateIntRealSig{
2768+
baseBuiltinFunc: bf,
2769+
baseDateArithmitical: newDateArighmeticalUtil(),
2770+
}
27472771
case dateEvalTp == types.ETInt && intervalEvalTp == types.ETDecimal:
27482772
sig = &builtinAddDateIntDecimalSig{
27492773
baseBuiltinFunc: bf,
@@ -2759,6 +2783,11 @@ func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
27592783
baseBuiltinFunc: bf,
27602784
baseDateArithmitical: newDateArighmeticalUtil(),
27612785
}
2786+
case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETReal:
2787+
sig = &builtinAddDateDatetimeRealSig{
2788+
baseBuiltinFunc: bf,
2789+
baseDateArithmitical: newDateArighmeticalUtil(),
2790+
}
27622791
case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETDecimal:
27632792
sig = &builtinAddDateDatetimeDecimalSig{
27642793
baseBuiltinFunc: bf,
@@ -2834,6 +2863,39 @@ func (b *builtinAddDateStringIntSig) evalTime(row chunk.Row) (types.Time, bool,
28342863
return result, isNull || err != nil, errors.Trace(err)
28352864
}
28362865

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

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

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

30823210
intervalEvalTp := args[1].GetType().EvalType()
3083-
if intervalEvalTp != types.ETString && intervalEvalTp != types.ETDecimal {
3211+
if intervalEvalTp != types.ETString && intervalEvalTp != types.ETDecimal && intervalEvalTp != types.ETReal {
30843212
intervalEvalTp = types.ETInt
30853213
}
30863214

@@ -3099,6 +3227,11 @@ func (c *subDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
30993227
baseBuiltinFunc: bf,
31003228
baseDateArithmitical: newDateArighmeticalUtil(),
31013229
}
3230+
case dateEvalTp == types.ETString && intervalEvalTp == types.ETReal:
3231+
sig = &builtinSubDateStringRealSig{
3232+
baseBuiltinFunc: bf,
3233+
baseDateArithmitical: newDateArighmeticalUtil(),
3234+
}
31023235
case dateEvalTp == types.ETString && intervalEvalTp == types.ETDecimal:
31033236
sig = &builtinSubDateStringDecimalSig{
31043237
baseBuiltinFunc: bf,
@@ -3114,6 +3247,11 @@ func (c *subDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
31143247
baseBuiltinFunc: bf,
31153248
baseDateArithmitical: newDateArighmeticalUtil(),
31163249
}
3250+
case dateEvalTp == types.ETInt && intervalEvalTp == types.ETReal:
3251+
sig = &builtinSubDateIntRealSig{
3252+
baseBuiltinFunc: bf,
3253+
baseDateArithmitical: newDateArighmeticalUtil(),
3254+
}
31173255
case dateEvalTp == types.ETInt && intervalEvalTp == types.ETDecimal:
31183256
sig = &builtinSubDateIntDecimalSig{
31193257
baseBuiltinFunc: bf,
@@ -3129,6 +3267,11 @@ func (c *subDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
31293267
baseBuiltinFunc: bf,
31303268
baseDateArithmitical: newDateArighmeticalUtil(),
31313269
}
3270+
case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETReal:
3271+
sig = &builtinSubDateDatetimeRealSig{
3272+
baseBuiltinFunc: bf,
3273+
baseDateArithmitical: newDateArighmeticalUtil(),
3274+
}
31323275
case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETDecimal:
31333276
sig = &builtinSubDateDatetimeDecimalSig{
31343277
baseBuiltinFunc: bf,
@@ -3204,6 +3347,39 @@ func (b *builtinSubDateStringIntSig) evalTime(row chunk.Row) (types.Time, bool,
32043347
return result, isNull || err != nil, errors.Trace(err)
32053348
}
32063349

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

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

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

expression/integration_test.go

+22
Original file line numberDiff line numberDiff line change
@@ -3957,3 +3957,25 @@ func (s *testIntegrationSuite) TestTimestampDatumEncode(c *C) {
39573957
))
39583958
tk.MustQuery(`select * from t where b = (select max(b) from t)`).Check(testkit.Rows(`1 2019-04-29 11:56:12`))
39593959
}
3960+
3961+
func (s *testIntegrationSuite) TestDateTimeAddReal(c *C) {
3962+
tk := testkit.NewTestKit(c, s.store)
3963+
defer s.cleanEnv(c)
3964+
3965+
cases := []struct {
3966+
sql string
3967+
result string
3968+
}{
3969+
{`SELECT "1900-01-01 00:00:00" + INTERVAL 1.123456789e3 SECOND;`, "1900-01-01 00:18:43.456789"},
3970+
{`SELECT 19000101000000 + INTERVAL 1.123456789e3 SECOND;`, "1900-01-01 00:18:43.456789"},
3971+
{`select date("1900-01-01") + interval 1.123456789e3 second;`, "1900-01-01 00:18:43.456789"},
3972+
{`SELECT "1900-01-01 00:18:43.456789" - INTERVAL 1.123456789e3 SECOND;`, "1900-01-01 00:00:00"},
3973+
{`SELECT 19000101001843.456789 - INTERVAL 1.123456789e3 SECOND;`, "1900-01-01 00:00:00"},
3974+
{`select date("1900-01-01") - interval 1.123456789e3 second;`, "1899-12-31 23:41:16.543211"},
3975+
{`select 19000101000000 - interval 1.123456789e3 second;`, "1899-12-31 23:41:16.543211"},
3976+
}
3977+
3978+
for _, c := range cases {
3979+
tk.MustQuery(c.sql).Check(testkit.Rows(c.result))
3980+
}
3981+
}

0 commit comments

Comments
 (0)