From 02ee4c612186c3c0a341cefef8c49e0ada7280ac Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Thu, 21 Nov 2024 09:00:38 +0800 Subject: [PATCH] executor: fix incorrect result produced by addtime() or subtime() function when using the date type (#57337) (#57569) close pingcap/tidb#56861 --- pkg/expression/builtin_time.go | 97 ++++- pkg/expression/builtin_time_test.go | 374 ++++++++++++++++ pkg/expression/builtin_time_vec_generated.go | 102 +++-- pkg/expression/generator/time_vec.go | 56 +-- .../integration_test/integration_test.go | 12 +- .../integrationtest/r/expression/time.result | 402 ++++++++++++++++++ tests/integrationtest/t/expression/time.test | 78 ++++ 7 files changed, 1057 insertions(+), 64 deletions(-) diff --git a/pkg/expression/builtin_time.go b/pkg/expression/builtin_time.go index f32afd272a1d2..9629912f11e6b 100644 --- a/pkg/expression/builtin_time.go +++ b/pkg/expression/builtin_time.go @@ -4579,7 +4579,7 @@ func getBf4TimeAddSub(ctx BuildContext, funcName string, args []Expression) (tp1 case mysql.TypeDuration: argTp1, retTp = types.ETDuration, types.ETDuration case mysql.TypeDate: - argTp1, retTp = types.ETDuration, types.ETString + argTp1, retTp = types.ETDatetime, types.ETString default: argTp1, retTp = types.ETString, types.ETString } @@ -4804,11 +4804,20 @@ func (b *builtinAddDatetimeAndDurationSig) evalTime(ctx EvalContext, row chunk.R if isNull || err != nil { return types.ZeroDatetime, isNull, err } + + if arg0.IsZero() { + return types.ZeroDatetime, true, nil + } + arg1, isNull, err := b.args[1].EvalDuration(ctx, row) if isNull || err != nil { return types.ZeroDatetime, isNull, err } result, err := arg0.Add(typeCtx(ctx), arg1) + if err != nil { + return types.ZeroDatetime, true, err + } + return result, err != nil, err } @@ -4829,6 +4838,11 @@ func (b *builtinAddDatetimeAndStringSig) evalTime(ctx EvalContext, row chunk.Row if isNull || err != nil { return types.ZeroDatetime, isNull, err } + + if arg0.IsZero() { + return types.ZeroDatetime, true, nil + } + s, isNull, err := b.args[1].EvalString(ctx, row) if isNull || err != nil { return types.ZeroDatetime, isNull, err @@ -4846,6 +4860,10 @@ func (b *builtinAddDatetimeAndStringSig) evalTime(ctx EvalContext, row chunk.Row return types.ZeroDatetime, true, err } result, err := arg0.Add(tc, arg1) + if err != nil { + return types.ZeroDatetime, true, err + } + return result, err != nil, err } @@ -5066,15 +5084,26 @@ func (b *builtinAddDateAndDurationSig) Clone() builtinFunc { // evalString evals a builtinAddDurationAndDurationSig. // See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_addtime func (b *builtinAddDateAndDurationSig) evalString(ctx EvalContext, row chunk.Row) (string, bool, error) { - arg0, isNull, err := b.args[0].EvalDuration(ctx, row) + arg0, isNull, err := b.args[0].EvalTime(ctx, row) if isNull || err != nil { return "", isNull, err } + + if arg0.IsZero() { + return "", true, nil + } + arg1, isNull, err := b.args[1].EvalDuration(ctx, row) if isNull || err != nil { return "", isNull, err } - result, err := arg0.Add(arg1) + + arg0.SetType(mysql.TypeDatetime) + result, err := arg0.Add(typeCtx(ctx), arg1) + if err != nil { + return "", true, err + } + return result.String(), err != nil, err } @@ -5091,10 +5120,15 @@ func (b *builtinAddDateAndStringSig) Clone() builtinFunc { // evalString evals a builtinAddDateAndStringSig. // See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_addtime func (b *builtinAddDateAndStringSig) evalString(ctx EvalContext, row chunk.Row) (string, bool, error) { - arg0, isNull, err := b.args[0].EvalDuration(ctx, row) + arg0, isNull, err := b.args[0].EvalTime(ctx, row) if isNull || err != nil { return "", isNull, err } + + if arg0.IsZero() { + return "", true, nil + } + s, isNull, err := b.args[1].EvalString(ctx, row) if isNull || err != nil { return "", isNull, err @@ -5111,7 +5145,13 @@ func (b *builtinAddDateAndStringSig) evalString(ctx EvalContext, row chunk.Row) } return "", true, err } - result, err := arg0.Add(arg1) + + arg0.SetType(mysql.TypeDatetime) + result, err := arg0.Add(tc, arg1) + if err != nil { + return "", true, err + } + return result.String(), err != nil, err } @@ -5757,12 +5797,21 @@ func (b *builtinSubDatetimeAndDurationSig) evalTime(ctx EvalContext, row chunk.R if isNull || err != nil { return types.ZeroDatetime, isNull, err } + + if arg0.IsZero() { + return types.ZeroDatetime, true, nil + } + arg1, isNull, err := b.args[1].EvalDuration(ctx, row) if isNull || err != nil { return types.ZeroDatetime, isNull, err } tc := typeCtx(ctx) result, err := arg0.Add(tc, arg1.Neg()) + if err != nil { + return types.ZeroDatetime, true, err + } + return result, err != nil, err } @@ -5783,6 +5832,11 @@ func (b *builtinSubDatetimeAndStringSig) evalTime(ctx EvalContext, row chunk.Row if isNull || err != nil { return types.ZeroDatetime, isNull, err } + + if arg0.IsZero() { + return types.ZeroDatetime, true, nil + } + s, isNull, err := b.args[1].EvalString(ctx, row) if isNull || err != nil { return types.ZeroDatetime, isNull, err @@ -5800,6 +5854,10 @@ func (b *builtinSubDatetimeAndStringSig) evalTime(ctx EvalContext, row chunk.Row return types.ZeroDatetime, true, err } result, err := arg0.Add(tc, arg1.Neg()) + if err != nil { + return types.ZeroDatetime, true, err + } + return result, err != nil, err } @@ -6023,15 +6081,26 @@ func (b *builtinSubDateAndDurationSig) Clone() builtinFunc { // evalString evals a builtinSubDateAndDurationSig. // See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subtime func (b *builtinSubDateAndDurationSig) evalString(ctx EvalContext, row chunk.Row) (string, bool, error) { - arg0, isNull, err := b.args[0].EvalDuration(ctx, row) + arg0, isNull, err := b.args[0].EvalTime(ctx, row) if isNull || err != nil { return "", isNull, err } + + if arg0.IsZero() { + return "", true, nil + } + arg1, isNull, err := b.args[1].EvalDuration(ctx, row) if isNull || err != nil { return "", isNull, err } - result, err := arg0.Sub(arg1) + + arg0.SetType(mysql.TypeDatetime) + result, err := arg0.Add(typeCtx(ctx), arg1.Neg()) + if err != nil { + return "", true, err + } + return result.String(), err != nil, err } @@ -6048,10 +6117,15 @@ func (b *builtinSubDateAndStringSig) Clone() builtinFunc { // evalString evals a builtinSubDateAndStringSig. // See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subtime func (b *builtinSubDateAndStringSig) evalString(ctx EvalContext, row chunk.Row) (string, bool, error) { - arg0, isNull, err := b.args[0].EvalDuration(ctx, row) + arg0, isNull, err := b.args[0].EvalTime(ctx, row) if isNull || err != nil { return "", isNull, err } + + if arg0.IsZero() { + return "", true, nil + } + s, isNull, err := b.args[1].EvalString(ctx, row) if isNull || err != nil { return "", isNull, err @@ -6068,11 +6142,14 @@ func (b *builtinSubDateAndStringSig) evalString(ctx EvalContext, row chunk.Row) } return "", true, err } - result, err := arg0.Sub(arg1) + + arg0.SetType(mysql.TypeDatetime) + result, err := arg0.Add(tc, arg1.Neg()) if err != nil { return "", true, err } - return result.String(), false, nil + + return result.String(), err != nil, err } type timeFormatFunctionClass struct { diff --git a/pkg/expression/builtin_time_test.go b/pkg/expression/builtin_time_test.go index 60505be7f916f..1de80bbb2cf34 100644 --- a/pkg/expression/builtin_time_test.go +++ b/pkg/expression/builtin_time_test.go @@ -1025,6 +1025,194 @@ func TestAddTimeSig(t *testing.T) { require.Equal(t, i+1+beforeWarnCnt, len(warnings)) require.Truef(t, terror.ErrorEqual(c.warning, warnings[i].Err), "err %v", warnings[i].Err) } + + addTimeTestForIssue56861(t, ctx, fc) +} + +func addTimeTestForIssue56861(t *testing.T, ctx *mock.Context, fc functionClass) { + dateStringCases := []struct { + arg0 types.Time + isArg0Null bool + arg1 string + isArg1Null bool + expect string + isExpectNull bool + }{ + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, "12:00:01.341300", false, "2024-11-01 12:00:01.341300", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, "-12:00:01.341300", false, "2024-10-31 11:59:58.658700", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, "1 12:00:01.341300", false, "2024-11-02 12:00:01.341300", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, "-1 12:00:01.341300", false, "2024-10-30 11:59:58.658700", false}, + {types.NewTime(types.FromDate(1000, 1, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, "12:00:01.341300", false, "1000-01-01 12:00:01.341300", false}, + {types.NewTime(types.FromDate(1000, 1, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, "-12:00:01.341300", false, "0999-12-31 11:59:58.658700", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDate, 0), false, "12:00:01.341300", false, "9999-12-31 12:00:01.341300", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDate, 0), false, "-12:00:01.341300", false, "9999-12-30 11:59:58.658700", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDate, 0), false, "anuverivr", false, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), true, "", false, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, "", true, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), true, "", true, "", true}, + } + + for _, c := range dateStringCases { + exprs := make([]Expression, 2) + arg0Datum := types.NewTimeDatum(c.arg0) + if c.isArg0Null { + arg0Datum.SetNull() + } + arg1Datum := types.NewStringDatum(c.arg1) + if c.isArg1Null { + arg1Datum.SetNull() + } + exprs[0] = &Constant{Value: arg0Datum, RetType: types.NewFieldType(mysql.TypeDate)} + exprs[1] = &Constant{Value: arg1Datum, RetType: types.NewFieldType(mysql.TypeVarString)} + f, err := fc.getFunction(ctx, exprs) + require.NoError(t, err) + d, err := evalBuiltinFunc(f, ctx, chunk.Row{}) + if c.isExpectNull { + require.True(t, d.IsNull()) + continue + } + require.NoError(t, err) + result, _ := d.ToString() + require.Equal(t, c.expect, result) + } + + dateDurationCases := []struct { + arg0 types.Time + isArg0Null bool + arg1 types.Duration + isArg1Null bool + expect string + isExpectNull bool + }{ + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(12, 0, 1, 0, 0), false, "2024-11-01 12:00:01", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(12, 0, 1, 0, 0).Neg(), false, "2024-10-31 11:59:59", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(36, 0, 1, 0, 0), false, "2024-11-02 12:00:01", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(36, 0, 1, 0, 0).Neg(), false, "2024-10-30 11:59:59", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(0, 0, 0, 0, 0), false, "2024-11-01 00:00:00", false}, + {types.NewTime(types.FromDate(1000, 1, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(12, 0, 1, 0, 0), false, "1000-01-01 12:00:01", false}, + {types.NewTime(types.FromDate(1000, 1, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(12, 0, 1, 0, 0).Neg(), false, "0999-12-31 11:59:59", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(12, 0, 1, 0, 0), false, "9999-12-31 12:00:01", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(12, 0, 1, 0, 0).Neg(), false, "9999-12-30 11:59:59", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), true, types.NewDuration(0, 0, 0, 0, 0), false, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(0, 0, 0, 0, 0), true, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), true, types.NewDuration(0, 0, 0, 0, 0), true, "", true}, + } + + for _, c := range dateDurationCases { + exprs := make([]Expression, 2) + arg0Datum := types.NewTimeDatum(c.arg0) + if c.isArg0Null { + arg0Datum.SetNull() + } + arg1Datum := types.NewDurationDatum(c.arg1) + if c.isArg1Null { + arg1Datum.SetNull() + } + exprs[0] = &Constant{Value: arg0Datum, RetType: types.NewFieldType(mysql.TypeDate)} + exprs[1] = &Constant{Value: arg1Datum, RetType: types.NewFieldType(mysql.TypeVarString)} + f, err := fc.getFunction(ctx, exprs) + require.NoError(t, err) + d, err := evalBuiltinFunc(f, ctx, chunk.Row{}) + if c.isExpectNull { + require.True(t, d.IsNull()) + continue + } + require.NoError(t, err) + result, _ := d.ToString() + require.Equal(t, c.expect, result) + } + + datetimeStringCases := []struct { + arg0 types.Time + isArg0Null bool + arg1 string + isArg1Null bool + expect string + isExpectNull bool + }{ + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "12:00:01.341300", false, "2024-11-01 12:00:01.341300", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "-12:00:01.341300", false, "2024-10-31 11:59:58.658700", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "1 12:00:01.341300", false, "2024-11-02 12:00:01.341300", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "-1 12:00:01.341300", false, "2024-10-30 11:59:58.658700", false}, + {types.NewTime(types.FromDate(1000, 1, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "12:00:01.341300", false, "1000-01-01 12:00:01.341300", false}, + {types.NewTime(types.FromDate(1000, 1, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "-12:00:01.341300", false, "0999-12-31 11:59:58.658700", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "12:00:01.341300", false, "9999-12-31 12:00:01.341300", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "-12:00:01.341300", false, "9999-12-30 11:59:58.658700", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "anuverivr", false, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), true, "", false, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "", true, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), true, "", true, "", true}, + } + + for _, c := range datetimeStringCases { + exprs := make([]Expression, 2) + arg0Datum := types.NewTimeDatum(c.arg0) + if c.isArg0Null { + arg0Datum.SetNull() + } + arg1Datum := types.NewStringDatum(c.arg1) + if c.isArg1Null { + arg1Datum.SetNull() + } + exprs[0] = &Constant{Value: arg0Datum, RetType: types.NewFieldType(mysql.TypeDate)} + exprs[1] = &Constant{Value: arg1Datum, RetType: types.NewFieldType(mysql.TypeVarString)} + f, err := fc.getFunction(ctx, exprs) + require.NoError(t, err) + d, err := evalBuiltinFunc(f, ctx, chunk.Row{}) + if c.isExpectNull { + require.True(t, d.IsNull()) + continue + } + require.NoError(t, err) + result, _ := d.ToString() + require.Equal(t, c.expect, result) + } + + datetimeDurationCases := []struct { + arg0 types.Time + isArg0Null bool + arg1 types.Duration + isArg1Null bool + expect string + isExpectNull bool + }{ + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(12, 0, 1, 0, 0), false, "2024-11-01 12:00:01", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(12, 0, 1, 0, 0).Neg(), false, "2024-10-31 11:59:59", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(36, 0, 1, 0, 0), false, "2024-11-02 12:00:01", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(36, 0, 1, 0, 0).Neg(), false, "2024-10-30 11:59:59", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(0, 0, 0, 0, 0), false, "2024-11-01 00:00:00", false}, + {types.NewTime(types.FromDate(1000, 1, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(12, 0, 1, 0, 0), false, "1000-01-01 12:00:01", false}, + {types.NewTime(types.FromDate(1000, 1, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(12, 0, 1, 0, 0).Neg(), false, "0999-12-31 11:59:59", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(12, 0, 1, 0, 0), false, "9999-12-31 12:00:01", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(12, 0, 1, 0, 0).Neg(), false, "9999-12-30 11:59:59", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), true, types.NewDuration(0, 0, 0, 0, 0), false, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(0, 0, 0, 0, 0), true, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), true, types.NewDuration(0, 0, 0, 0, 0), true, "", true}, + } + + for _, c := range datetimeDurationCases { + exprs := make([]Expression, 2) + arg0Datum := types.NewTimeDatum(c.arg0) + if c.isArg0Null { + arg0Datum.SetNull() + } + arg1Datum := types.NewDurationDatum(c.arg1) + if c.isArg1Null { + arg1Datum.SetNull() + } + exprs[0] = &Constant{Value: arg0Datum, RetType: types.NewFieldType(mysql.TypeDate)} + exprs[1] = &Constant{Value: arg1Datum, RetType: types.NewFieldType(mysql.TypeVarString)} + f, err := fc.getFunction(ctx, exprs) + require.NoError(t, err) + d, err := evalBuiltinFunc(f, ctx, chunk.Row{}) + if c.isExpectNull { + require.True(t, d.IsNull()) + continue + } + require.NoError(t, err) + result, _ := d.ToString() + require.Equal(t, c.expect, result) + } } func TestSubTimeSig(t *testing.T) { @@ -1125,6 +1313,192 @@ func TestSubTimeSig(t *testing.T) { require.Equal(t, i+1+beforeWarnCnt, len(warnings)) require.Truef(t, terror.ErrorEqual(c.warning, warnings[i].Err), "err %v", warnings[i].Err) } + + subTimeTestForIssue56861(t, ctx, fc) +} + +func subTimeTestForIssue56861(t *testing.T, ctx *mock.Context, fc functionClass) { + dateStringCases := []struct { + arg0 types.Time + isArg0Null bool + arg1 string + isArg1Null bool + expect string + isExpectNull bool + }{ + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, "12:00:01.341300", false, "2024-10-31 11:59:58.658700", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, "-12:00:01.341300", false, "2024-11-01 12:00:01.341300", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, "1 12:00:01.341300", false, "2024-10-30 11:59:58.658700", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, "-1 12:00:01.341300", false, "2024-11-02 12:00:01.341300", false}, + {types.NewTime(types.FromDate(1000, 1, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, "12:00:01.341300", false, "0999-12-31 11:59:58.658700", false}, + {types.NewTime(types.FromDate(1000, 1, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, "-12:00:01.341300", false, "1000-01-01 12:00:01.341300", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDate, 0), false, "12:00:01.341300", false, "9999-12-30 11:59:58.658700", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDate, 0), false, "-12:00:01.341300", false, "9999-12-31 12:00:01.341300", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDate, 0), false, "anuverivr", false, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), true, "", false, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, "", true, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), true, "", true, "", true}, + } + + for _, c := range dateStringCases { + exprs := make([]Expression, 2) + arg0Datum := types.NewTimeDatum(c.arg0) + if c.isArg0Null { + arg0Datum.SetNull() + } + arg1Datum := types.NewStringDatum(c.arg1) + if c.isArg1Null { + arg1Datum.SetNull() + } + exprs[0] = &Constant{Value: arg0Datum, RetType: types.NewFieldType(mysql.TypeDate)} + exprs[1] = &Constant{Value: arg1Datum, RetType: types.NewFieldType(mysql.TypeVarString)} + f, err := fc.getFunction(ctx, exprs) + require.NoError(t, err) + d, err := evalBuiltinFunc(f, ctx, chunk.Row{}) + if c.isExpectNull { + require.True(t, d.IsNull()) + continue + } + require.NoError(t, err) + result, _ := d.ToString() + require.Equal(t, c.expect, result) + } + + dateDurationCases := []struct { + arg0 types.Time + isArg0Null bool + arg1 types.Duration + isArg1Null bool + expect string + isExpectNull bool + }{ + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(12, 0, 1, 0, 0), false, "2024-10-31 11:59:59", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(12, 0, 1, 0, 0).Neg(), false, "2024-11-01 12:00:01", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(36, 0, 1, 0, 0), false, "2024-10-30 11:59:59", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(36, 0, 1, 0, 0).Neg(), false, "2024-11-02 12:00:01", false}, + {types.NewTime(types.FromDate(1000, 1, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(12, 0, 1, 0, 0), false, "0999-12-31 11:59:59", false}, + {types.NewTime(types.FromDate(1000, 1, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(12, 0, 1, 0, 0).Neg(), false, "1000-01-01 12:00:01", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(12, 0, 1, 0, 0), false, "9999-12-30 11:59:59", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(12, 0, 1, 0, 0).Neg(), false, "9999-12-31 12:00:01", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), true, types.NewDuration(0, 0, 0, 0, 0), false, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), false, types.NewDuration(0, 0, 0, 0, 0), true, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDate, 0), true, types.NewDuration(0, 0, 0, 0, 0), true, "", true}, + } + + for _, c := range dateDurationCases { + exprs := make([]Expression, 2) + arg0Datum := types.NewTimeDatum(c.arg0) + if c.isArg0Null { + arg0Datum.SetNull() + } + arg1Datum := types.NewDurationDatum(c.arg1) + if c.isArg1Null { + arg1Datum.SetNull() + } + exprs[0] = &Constant{Value: arg0Datum, RetType: types.NewFieldType(mysql.TypeDate)} + exprs[1] = &Constant{Value: arg1Datum, RetType: types.NewFieldType(mysql.TypeDuration)} + f, err := fc.getFunction(ctx, exprs) + require.NoError(t, err) + d, err := evalBuiltinFunc(f, ctx, chunk.Row{}) + if c.isExpectNull { + require.True(t, d.IsNull()) + continue + } + require.NoError(t, err) + result, _ := d.ToString() + require.Equal(t, c.expect, result) + } + + datetimeStringCases := []struct { + arg0 types.Time + isArg0Null bool + arg1 string + isArg1Null bool + expect string + isExpectNull bool + }{ + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "12:00:01.341300", false, "2024-10-31 11:59:58.658700", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "-12:00:01.341300", false, "2024-11-01 12:00:01.341300", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "1 12:00:01.341300", false, "2024-10-30 11:59:58.658700", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "-1 12:00:01.341300", false, "2024-11-02 12:00:01.341300", false}, + {types.NewTime(types.FromDate(1000, 1, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "12:00:01.341300", false, "0999-12-31 11:59:58.658700", false}, + {types.NewTime(types.FromDate(1000, 1, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "-12:00:01.341300", false, "1000-01-01 12:00:01.341300", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "12:00:01.341300", false, "9999-12-30 11:59:58.658700", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "-12:00:01.341300", false, "9999-12-31 12:00:01.341300", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "anuverivr", false, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), true, "", false, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, "", true, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), true, "", true, "", true}, + } + + for _, c := range datetimeStringCases { + exprs := make([]Expression, 2) + arg0Datum := types.NewTimeDatum(c.arg0) + if c.isArg0Null { + arg0Datum.SetNull() + } + arg1Datum := types.NewStringDatum(c.arg1) + if c.isArg1Null { + arg1Datum.SetNull() + } + exprs[0] = &Constant{Value: arg0Datum, RetType: types.NewFieldType(mysql.TypeDate)} + exprs[1] = &Constant{Value: arg1Datum, RetType: types.NewFieldType(mysql.TypeVarString)} + f, err := fc.getFunction(ctx, exprs) + require.NoError(t, err) + d, err := evalBuiltinFunc(f, ctx, chunk.Row{}) + if c.isExpectNull { + require.True(t, d.IsNull()) + continue + } + require.NoError(t, err) + result, _ := d.ToString() + require.Equal(t, c.expect, result) + } + + datetimeDurationCases := []struct { + arg0 types.Time + isArg0Null bool + arg1 types.Duration + isArg1Null bool + expect string + isExpectNull bool + }{ + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(12, 0, 1, 0, 0), false, "2024-10-31 11:59:59", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(12, 0, 1, 0, 0).Neg(), false, "2024-11-01 12:00:01", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(36, 0, 1, 0, 0), false, "2024-10-30 11:59:59", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(36, 0, 1, 0, 0).Neg(), false, "2024-11-02 12:00:01", false}, + {types.NewTime(types.FromDate(1000, 1, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(12, 0, 1, 0, 0), false, "0999-12-31 11:59:59", false}, + {types.NewTime(types.FromDate(1000, 1, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(12, 0, 1, 0, 0).Neg(), false, "1000-01-01 12:00:01", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(12, 0, 1, 0, 0), false, "9999-12-30 11:59:59", false}, + {types.NewTime(types.FromDate(9999, 12, 31, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(12, 0, 1, 0, 0).Neg(), false, "9999-12-31 12:00:01", false}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), true, types.NewDuration(0, 0, 0, 0, 0), false, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), false, types.NewDuration(0, 0, 0, 0, 0), true, "", true}, + {types.NewTime(types.FromDate(2024, 11, 1, 0, 0, 0, 0), mysql.TypeDatetime, 0), true, types.NewDuration(0, 0, 0, 0, 0), true, "", true}, + } + + for _, c := range datetimeDurationCases { + exprs := make([]Expression, 2) + arg0Datum := types.NewTimeDatum(c.arg0) + if c.isArg0Null { + arg0Datum.SetNull() + } + arg1Datum := types.NewDurationDatum(c.arg1) + if c.isArg1Null { + arg1Datum.SetNull() + } + exprs[0] = &Constant{Value: arg0Datum, RetType: types.NewFieldType(mysql.TypeDate)} + exprs[1] = &Constant{Value: arg1Datum, RetType: types.NewFieldType(mysql.TypeDuration)} + f, err := fc.getFunction(ctx, exprs) + require.NoError(t, err) + d, err := evalBuiltinFunc(f, ctx, chunk.Row{}) + if c.isExpectNull { + require.True(t, d.IsNull()) + continue + } + require.NoError(t, err) + result, _ := d.ToString() + require.Equal(t, c.expect, result) + } } func TestSysDate(t *testing.T) { diff --git a/pkg/expression/builtin_time_vec_generated.go b/pkg/expression/builtin_time_vec_generated.go index 0ce537d4faac9..02b8eea2621a0 100644 --- a/pkg/expression/builtin_time_vec_generated.go +++ b/pkg/expression/builtin_time_vec_generated.go @@ -62,6 +62,11 @@ func (b *builtinAddDatetimeAndDurationSig) vecEvalTime(ctx EvalContext, input *c // calculate + if arg0.IsZero() { + result.SetNull(i, true) // fixed: true + continue + } + output, err := arg0.Add(typeCtx(ctx), types.Duration{Duration: arg1, Fsp: -1}) if err != nil { @@ -117,6 +122,11 @@ func (b *builtinAddDatetimeAndStringSig) vecEvalTime(ctx EvalContext, input *chu // calculate + if arg0.IsZero() { + result.SetNull(i, true) // fixed: true + continue + } + if !isDuration(arg1) { result.SetNull(i, true) // fixed: true continue @@ -464,7 +474,7 @@ func (b *builtinAddDateAndDurationSig) vecEvalString(ctx EvalContext, input *chu return err } defer b.bufAllocator.put(buf0) - if err := b.args[0].VecEvalDuration(ctx, input, buf0); err != nil { + if err := b.args[0].VecEvalTime(ctx, input, buf0); err != nil { return err } @@ -479,7 +489,7 @@ func (b *builtinAddDateAndDurationSig) vecEvalString(ctx EvalContext, input *chu result.ReserveString(n) - arg0s := buf0.GoDurations() + arg0s := buf0.Times() arg1s := buf1.GoDurations() @@ -498,16 +508,25 @@ func (b *builtinAddDateAndDurationSig) vecEvalString(ctx EvalContext, input *chu // calculate - fsp0 := b.args[0].GetType(ctx).GetDecimal() + if arg0.IsZero() { + result.AppendNull() // fixed: false + continue + } + fsp1 := b.args[1].GetType(ctx).GetDecimal() arg1Duration := types.Duration{Duration: arg1, Fsp: fsp1} + tc := typeCtx(ctx) + arg0.SetType(mysql.TypeDatetime) - sum, err := types.Duration{Duration: arg0, Fsp: fsp0}.Add(arg1Duration) + res, err := arg0.Add(tc, arg1Duration) if err != nil { - return err + tc.AppendWarning(err) + result.AppendNull() // fixed: false + continue } - output := sum.String() + + output := res.String() // commit result @@ -529,7 +548,7 @@ func (b *builtinAddDateAndStringSig) vecEvalString(ctx EvalContext, input *chunk return err } defer b.bufAllocator.put(buf0) - if err := b.args[0].VecEvalDuration(ctx, input, buf0); err != nil { + if err := b.args[0].VecEvalTime(ctx, input, buf0); err != nil { return err } @@ -544,7 +563,7 @@ func (b *builtinAddDateAndStringSig) vecEvalString(ctx EvalContext, input *chunk result.ReserveString(n) - arg0s := buf0.GoDurations() + arg0s := buf0.Times() for i := 0; i < n; i++ { @@ -561,6 +580,11 @@ func (b *builtinAddDateAndStringSig) vecEvalString(ctx EvalContext, input *chunk // calculate + if arg0.IsZero() { + result.AppendNull() // fixed: false + continue + } + if !isDuration(arg1) { result.AppendNull() // fixed: false continue @@ -576,14 +600,17 @@ func (b *builtinAddDateAndStringSig) vecEvalString(ctx EvalContext, input *chunk return err } - fsp0 := b.args[0].GetType(ctx).GetDecimal() + arg0.SetType(mysql.TypeDatetime) - sum, err := types.Duration{Duration: arg0, Fsp: fsp0}.Add(arg1Duration) + res, err := arg0.Add(tc, arg1Duration) if err != nil { - return err + tc.AppendWarning(err) + result.AppendNull() // fixed: false + continue } - output := sum.String() + + output := res.String() // commit result @@ -675,6 +702,11 @@ func (b *builtinSubDatetimeAndDurationSig) vecEvalTime(ctx EvalContext, input *c // calculate + if arg0.IsZero() { + result.SetNull(i, true) // fixed: true + continue + } + tc := typeCtx(ctx) arg1Duration := types.Duration{Duration: arg1, Fsp: -1} output, err := arg0.Add(tc, arg1Duration.Neg()) @@ -732,6 +764,11 @@ func (b *builtinSubDatetimeAndStringSig) vecEvalTime(ctx EvalContext, input *chu // calculate + if arg0.IsZero() { + result.SetNull(i, true) // fixed: true + continue + } + if !isDuration(arg1) { result.SetNull(i, true) // fixed: true continue @@ -1078,7 +1115,7 @@ func (b *builtinSubDateAndDurationSig) vecEvalString(ctx EvalContext, input *chu return err } defer b.bufAllocator.put(buf0) - if err := b.args[0].VecEvalDuration(ctx, input, buf0); err != nil { + if err := b.args[0].VecEvalTime(ctx, input, buf0); err != nil { return err } @@ -1093,7 +1130,7 @@ func (b *builtinSubDateAndDurationSig) vecEvalString(ctx EvalContext, input *chu result.ReserveString(n) - arg0s := buf0.GoDurations() + arg0s := buf0.Times() arg1s := buf1.GoDurations() @@ -1112,16 +1149,25 @@ func (b *builtinSubDateAndDurationSig) vecEvalString(ctx EvalContext, input *chu // calculate - fsp0 := b.args[0].GetType(ctx).GetDecimal() + if arg0.IsZero() { + result.AppendNull() // fixed: false + continue + } + fsp1 := b.args[1].GetType(ctx).GetDecimal() arg1Duration := types.Duration{Duration: arg1, Fsp: fsp1} + tc := typeCtx(ctx) + arg0.SetType(mysql.TypeDatetime) - sum, err := types.Duration{Duration: arg0, Fsp: fsp0}.Sub(arg1Duration) + res, err := arg0.Add(tc, arg1Duration.Neg()) if err != nil { - return err + tc.AppendWarning(err) + result.AppendNull() // fixed: false + continue } - output := sum.String() + + output := res.String() // commit result @@ -1143,7 +1189,7 @@ func (b *builtinSubDateAndStringSig) vecEvalString(ctx EvalContext, input *chunk return err } defer b.bufAllocator.put(buf0) - if err := b.args[0].VecEvalDuration(ctx, input, buf0); err != nil { + if err := b.args[0].VecEvalTime(ctx, input, buf0); err != nil { return err } @@ -1158,7 +1204,7 @@ func (b *builtinSubDateAndStringSig) vecEvalString(ctx EvalContext, input *chunk result.ReserveString(n) - arg0s := buf0.GoDurations() + arg0s := buf0.Times() for i := 0; i < n; i++ { @@ -1175,6 +1221,11 @@ func (b *builtinSubDateAndStringSig) vecEvalString(ctx EvalContext, input *chunk // calculate + if arg0.IsZero() { + result.AppendNull() // fixed: false + continue + } + if !isDuration(arg1) { result.AppendNull() // fixed: false continue @@ -1190,14 +1241,17 @@ func (b *builtinSubDateAndStringSig) vecEvalString(ctx EvalContext, input *chunk return err } - fsp0 := b.args[0].GetType(ctx).GetDecimal() + arg0.SetType(mysql.TypeDatetime) - sum, err := types.Duration{Duration: arg0, Fsp: fsp0}.Sub(arg1Duration) + res, err := arg0.Add(tc, arg1Duration.Neg()) if err != nil { - return err + tc.AppendWarning(err) + result.AppendNull() // fixed: false + continue } - output := sum.String() + + output := res.String() // commit result diff --git a/pkg/expression/generator/time_vec.go b/pkg/expression/generator/time_vec.go index a5c44831c11a0..3f31c9f9fe544 100644 --- a/pkg/expression/generator/time_vec.go +++ b/pkg/expression/generator/time_vec.go @@ -74,6 +74,13 @@ import ( } {{ end }} +{{ define "CheckZeroDate" }} + if arg0.IsZero() { + {{ template "SetNull" . }} + continue + } +{{ end }} + {{ range .Sigs }} {{ if .AllNull}} func (b *{{.SigName}}) vecEval{{ .Output.TypeName }}(ctx EvalContext, input *chunk.Chunk, result *chunk.Column) error { @@ -170,6 +177,7 @@ func (b *{{.SigName}}) vecEval{{ .Output.TypeName }}(ctx EvalContext, input *chu // calculate {{ if or (eq .SigName "builtinAddDatetimeAndDurationSig") (eq .SigName "builtinSubDatetimeAndDurationSig") }} + {{ template "CheckZeroDate" . }} {{ if eq $.FuncName "AddTime" }} output, err := arg0.Add(typeCtx(ctx), types.Duration{Duration: arg1, Fsp: -1}) {{ else }} @@ -182,6 +190,7 @@ func (b *{{.SigName}}) vecEval{{ .Output.TypeName }}(ctx EvalContext, input *chu } {{ else if or (eq .SigName "builtinAddDatetimeAndStringSig") (eq .SigName "builtinSubDatetimeAndStringSig") }} + {{ template "CheckZeroDate" . }} {{ if eq $.FuncName "AddTime" }} {{ template "ConvertStringToDuration" . }} output, err := arg0.Add(typeCtx(ctx), arg1Duration) @@ -299,30 +308,39 @@ func (b *{{.SigName}}) vecEval{{ .Output.TypeName }}(ctx EvalContext, input *chu } } {{ else if or (eq .SigName "builtinAddDateAndDurationSig") (eq .SigName "builtinSubDateAndDurationSig") }} - fsp0 := b.args[0].GetType(ctx).GetDecimal() + {{ template "CheckZeroDate" . }} fsp1 := b.args[1].GetType(ctx).GetDecimal() arg1Duration := types.Duration{Duration: arg1, Fsp: fsp1} + tc := typeCtx(ctx) + arg0.SetType(mysql.TypeDatetime) {{ if eq $.FuncName "AddTime" }} - sum, err := types.Duration{Duration: arg0, Fsp: fsp0}.Add(arg1Duration) + res, err := arg0.Add(tc, arg1Duration) {{ else }} - sum, err := types.Duration{Duration: arg0, Fsp: fsp0}.Sub(arg1Duration) + res, err := arg0.Add(tc, arg1Duration.Neg()) {{ end }} if err != nil { - return err + tc.AppendWarning(err) + {{ template "SetNull" . }} + continue } - output := sum.String() + + output := res.String() {{ else if or (eq .SigName "builtinAddDateAndStringSig") (eq .SigName "builtinSubDateAndStringSig") }} + {{ template "CheckZeroDate" . }} {{ template "ConvertStringToDuration" . }} - fsp0 := b.args[0].GetType(ctx).GetDecimal() + arg0.SetType(mysql.TypeDatetime) {{ if eq $.FuncName "AddTime" }} - sum, err := types.Duration{Duration: arg0, Fsp: fsp0}.Add(arg1Duration) + res, err := arg0.Add(tc, arg1Duration) {{ else }} - sum, err := types.Duration{Duration: arg0, Fsp: fsp0}.Sub(arg1Duration) + res, err := arg0.Add(tc, arg1Duration.Neg()) {{ end }} if err != nil { - return err + tc.AppendWarning(err) + {{ template "SetNull" . }} + continue } - output := sum.String() + + output := res.String() {{ end }} // commit result @@ -684,22 +702,13 @@ func (g gener) gen() any { // {{ $sig.SigName }} { retEvalType: types.ET{{ .Output.ETName }}, - {{- if eq .TestTypeA "" }} childrenTypes: []types.EvalType{types.ET{{ .TypeA.ETName }}, types.ET{{ .TypeB.ETName }}}, - {{- else }} - childrenTypes: []types.EvalType{types.ET{{ .TestTypeA }}, types.ET{{ .TestTypeB }}}, - {{- end }} {{- if ne .FieldTypeA "" }} childrenFieldTypes: []*types.FieldType{types.NewFieldType(mysql.Type{{.FieldTypeA}}), types.NewFieldType(mysql.Type{{.FieldTypeB}})}, {{- end }} geners: []dataGenerator{ - {{- if eq .TestTypeA "" }} gener{*newDefaultGener(0.2, types.ET{{.TypeA.ETName}})}, gener{*newDefaultGener(0.2, types.ET{{.TypeB.ETName}})}, - {{- else }} - gener{*newDefaultGener(0.2, types.ET{{ .TestTypeA }})}, - gener{*newDefaultGener(0.2, types.ET{{ .TestTypeB }})}, - {{- end }} }, }, {{- end }} @@ -785,8 +794,8 @@ var addTimeSigsTmpl = []sig{ {SigName: "builtinAddDurationAndStringSig", TypeA: TypeDuration, TypeB: TypeString, Output: TypeDuration}, {SigName: "builtinAddStringAndDurationSig", TypeA: TypeString, TypeB: TypeDuration, Output: TypeString}, {SigName: "builtinAddStringAndStringSig", TypeA: TypeString, TypeB: TypeString, Output: TypeString}, - {SigName: "builtinAddDateAndDurationSig", TypeA: TypeDuration, TypeB: TypeDuration, Output: TypeString, FieldTypeA: "Date", FieldTypeB: "Duration", TestTypeA: "Datetime", TestTypeB: "Duration"}, - {SigName: "builtinAddDateAndStringSig", TypeA: TypeDuration, TypeB: TypeString, Output: TypeString, FieldTypeA: "Date", FieldTypeB: "String", TestTypeA: "Datetime", TestTypeB: "String"}, + {SigName: "builtinAddDateAndDurationSig", TypeA: TypeDatetime, TypeB: TypeDuration, Output: TypeString, FieldTypeA: "Date", FieldTypeB: "Duration"}, + {SigName: "builtinAddDateAndStringSig", TypeA: TypeDatetime, TypeB: TypeString, Output: TypeString, FieldTypeA: "Date", FieldTypeB: "String"}, {SigName: "builtinAddTimeDateTimeNullSig", TypeA: TypeDatetime, TypeB: TypeDatetime, Output: TypeDatetime, AllNull: true}, {SigName: "builtinAddTimeStringNullSig", TypeA: TypeDatetime, TypeB: TypeDatetime, Output: TypeString, AllNull: true, FieldTypeA: "Date", FieldTypeB: "Datetime"}, @@ -800,8 +809,8 @@ var subTimeSigsTmpl = []sig{ {SigName: "builtinSubDurationAndStringSig", TypeA: TypeDuration, TypeB: TypeString, Output: TypeDuration}, {SigName: "builtinSubStringAndDurationSig", TypeA: TypeString, TypeB: TypeDuration, Output: TypeString}, {SigName: "builtinSubStringAndStringSig", TypeA: TypeString, TypeB: TypeString, Output: TypeString}, - {SigName: "builtinSubDateAndDurationSig", TypeA: TypeDuration, TypeB: TypeDuration, Output: TypeString, FieldTypeA: "Date", FieldTypeB: "Duration", TestTypeA: "Datetime", TestTypeB: "Duration"}, - {SigName: "builtinSubDateAndStringSig", TypeA: TypeDuration, TypeB: TypeString, Output: TypeString, FieldTypeA: "Date", FieldTypeB: "String", TestTypeA: "Datetime", TestTypeB: "String"}, + {SigName: "builtinSubDateAndDurationSig", TypeA: TypeDatetime, TypeB: TypeDuration, Output: TypeString, FieldTypeA: "Date", FieldTypeB: "Duration"}, + {SigName: "builtinSubDateAndStringSig", TypeA: TypeDatetime, TypeB: TypeString, Output: TypeString, FieldTypeA: "Date", FieldTypeB: "String"}, {SigName: "builtinSubTimeDateTimeNullSig", TypeA: TypeDatetime, TypeB: TypeDatetime, Output: TypeDatetime, AllNull: true}, {SigName: "builtinSubTimeStringNullSig", TypeA: TypeDatetime, TypeB: TypeDatetime, Output: TypeString, AllNull: true, FieldTypeA: "Date", FieldTypeB: "Datetime"}, @@ -893,7 +902,6 @@ type sig struct { SigName string TypeA, TypeB, Output TypeContext FieldTypeA, FieldTypeB string // Optional - TestTypeA, TestTypeB string // Optional, specific Type for test in builtinAddDateAndDurationSig & builtinAddDateAndStringSig AllNull bool } diff --git a/pkg/expression/integration_test/integration_test.go b/pkg/expression/integration_test/integration_test.go index 8a78d964d670b..d4825017e49ea 100644 --- a/pkg/expression/integration_test/integration_test.go +++ b/pkg/expression/integration_test/integration_test.go @@ -2499,13 +2499,13 @@ func TestTimeBuiltin(t *testing.T) { result = tk.MustQuery("select addtime(cast('01:01:11' as time(4)), '00:00:01.013'), addtime(cast('01:01:11.00' " + "as datetime(3)), '00:00:01')," + " addtime(cast('2017-01-01 01:01:11.12' as date), '00:00:01'), addtime(cast" + "(cast('2017-01-01 01:01:11.12' as date) as datetime(2)), '00:00:01.88');") - result.Check(testkit.Rows("01:01:12.0130 2001-01-11 00:00:01.000 00:00:01 2017-01-01 00:00:01.88")) + result.Check(testkit.Rows("01:01:12.0130 2001-01-11 00:00:01.000 2017-01-01 00:00:01 2017-01-01 00:00:01.88")) result = tk.MustQuery("select addtime('2017-01-01 01:01:01', 5), addtime('2017-01-01 01:01:01', -5), addtime('2017-01-01 01:01:01', 0.0), addtime('2017-01-01 01:01:01', 1.34);") result.Check(testkit.Rows("2017-01-01 01:01:06 2017-01-01 01:00:56 2017-01-01 01:01:01 2017-01-01 01:01:02.340000")) result = tk.MustQuery("select addtime(cast('01:01:11.00' as datetime(3)), cast('00:00:01' as time)), addtime(cast('01:01:11.00' as datetime(3)), cast('00:00:01' as time(5)))") result.Check(testkit.Rows("2001-01-11 00:00:01.000 2001-01-11 00:00:01.00000")) result = tk.MustQuery("select addtime(cast('01:01:11.00' as date), cast('00:00:01' as time));") - result.Check(testkit.Rows("00:00:01")) + result.Check(testkit.Rows("2001-01-11 00:00:01")) tk.MustExec("drop table if exists t") tk.MustExec("create table t(a datetime, b timestamp, c time)") tk.MustExec(`insert into t values("2017-01-01 12:30:31", "2017-01-01 12:30:31", "01:01:01")`) @@ -2529,7 +2529,7 @@ func TestTimeBuiltin(t *testing.T) { result = tk.MustQuery("select subtime(cast('01:01:11' as time(4)), '00:00:01.013'), subtime(cast('01:01:11.00' " + "as datetime(3)), '00:00:01')," + " subtime(cast('2017-01-01 01:01:11.12' as date), '00:00:01'), subtime(cast" + "(cast('2017-01-01 01:01:11.12' as date) as datetime(2)), '00:00:01.88');") - result.Check(testkit.Rows("01:01:09.9870 2001-01-10 23:59:59.000 -00:00:01 2016-12-31 23:59:58.12")) + result.Check(testkit.Rows("01:01:09.9870 2001-01-10 23:59:59.000 2016-12-31 23:59:59 2016-12-31 23:59:58.12")) result = tk.MustQuery("select subtime('2017-01-01 01:01:01', 5), subtime('2017-01-01 01:01:01', -5), subtime('2017-01-01 01:01:01', 0.0), subtime('2017-01-01 01:01:01', 1.34);") result.Check(testkit.Rows("2017-01-01 01:00:56 2017-01-01 01:01:06 2017-01-01 01:01:01 2017-01-01 01:00:59.660000")) result = tk.MustQuery("select subtime('01:01:11', '0:0:1.013'), subtime('01:01:11.00', '0:0:1'), subtime('2017-01-01 01:01:11.12', '0:0:1'), subtime('2017-01-01 01:01:11.12', '0:0:1.120000');") @@ -2537,7 +2537,7 @@ func TestTimeBuiltin(t *testing.T) { result = tk.MustQuery("select subtime(cast('01:01:11.00' as datetime(3)), cast('00:00:01' as time)), subtime(cast('01:01:11.00' as datetime(3)), cast('00:00:01' as time(5)))") result.Check(testkit.Rows("2001-01-10 23:59:59.000 2001-01-10 23:59:59.00000")) result = tk.MustQuery("select subtime(cast('01:01:11.00' as date), cast('00:00:01' as time));") - result.Check(testkit.Rows("-00:00:01")) + result.Check(testkit.Rows("2001-01-10 23:59:59")) result = tk.MustQuery("select subtime(a, b), subtime(cast(a as date), b), subtime(b,a), subtime(a,c), subtime(b," + "c), subtime(c,a), subtime(c,b) from t;") result.Check(testkit.Rows(" 2017-01-01 11:29:30 2017-01-01 11:29:30 ")) @@ -2561,13 +2561,13 @@ func TestTimeBuiltin(t *testing.T) { result = tk.MustQuery("select addtime('2017-01-01 01:01:01', 0b1), addtime('2017-01-01', b'1'), addtime('01:01:01', 0b1011)") result.Check(testkit.Rows(" ")) result = tk.MustQuery("select addtime('2017-01-01', 1), addtime('2017-01-01 01:01:01', 1), addtime(cast('2017-01-01' as date), 1)") - result.Check(testkit.Rows("2017-01-01 00:00:01 2017-01-01 01:01:02 00:00:01")) + result.Check(testkit.Rows("2017-01-01 00:00:01 2017-01-01 01:01:02 2017-01-01 00:00:01")) result = tk.MustQuery("select subtime(a, e), subtime(b, e), subtime(c, e), subtime(d, e) from t") result.Check(testkit.Rows(" ")) result = tk.MustQuery("select subtime('2017-01-01 01:01:01', 0b1), subtime('2017-01-01', b'1'), subtime('01:01:01', 0b1011)") result.Check(testkit.Rows(" ")) result = tk.MustQuery("select subtime('2017-01-01', 1), subtime('2017-01-01 01:01:01', 1), subtime(cast('2017-01-01' as date), 1)") - result.Check(testkit.Rows("2016-12-31 23:59:59 2017-01-01 01:01:00 -00:00:01")) + result.Check(testkit.Rows("2016-12-31 23:59:59 2017-01-01 01:01:00 2016-12-31 23:59:59")) result = tk.MustQuery("select addtime(-32073, 0), addtime(0, -32073);") result.Check(testkit.Rows(" ")) diff --git a/tests/integrationtest/r/expression/time.result b/tests/integrationtest/r/expression/time.result index 0888b7c8b701f..7fac5831cc57a 100644 --- a/tests/integrationtest/r/expression/time.result +++ b/tests/integrationtest/r/expression/time.result @@ -1064,3 +1064,405 @@ a d -1.00 0999-01-01 00:00:00 1.00 1001-01-01 00:00:00 drop table if exists t1; +drop table if exists t; +create table t(col0 date, col1 time, col2 varchar(30)); +insert into t values('2024-11-01', '12:00:01.341300', '12:00:01.341300'), ('2024-11-01', '1 12:00:01.341300', '1 12:00:01.341300'), ('2024-11-01', '-1 12:00:01.341300', '-1 12:00:01.341300'),('1000-01-01', '12:00:01.341300', '12:00:01.341300'), ('9999-12-31', '12:00:01.341300', '12:00:01.341300'), (null, '12:00:01.341300', '12:00:01.341300'), ('2020-11-01', null, null); +select addtime(date '2024-11-01', '12:00:01.341300'); +addtime(date '2024-11-01', '12:00:01.341300') +2024-11-01 12:00:01.341300 +select subtime(date '2024-11-01', '12:00:01.341300'); +subtime(date '2024-11-01', '12:00:01.341300') +2024-10-31 11:59:58.658700 +select addtime(date '2024-11-01', '1 12:00:01.341300'); +addtime(date '2024-11-01', '1 12:00:01.341300') +2024-11-02 12:00:01.341300 +select subtime(date '2024-11-01', '1 12:00:01.341300'); +subtime(date '2024-11-01', '1 12:00:01.341300') +2024-10-30 11:59:58.658700 +select addtime(date '2024-11-01', '-1 12:00:01.341300'); +addtime(date '2024-11-01', '-1 12:00:01.341300') +2024-10-30 11:59:58.658700 +select subtime(date '2024-11-01', '-1 12:00:01.341300'); +subtime(date '2024-11-01', '-1 12:00:01.341300') +2024-11-02 12:00:01.341300 +select addtime(date '2024-11-01', time '12:00:01.341300'); +addtime(date '2024-11-01', time '12:00:01.341300') +2024-11-01 12:00:01.341300 +select subtime(date '2024-11-01', time '12:00:01.341300'); +subtime(date '2024-11-01', time '12:00:01.341300') +2024-10-31 11:59:58.658700 +select addtime(date '2024-11-01', time '1 12:00:01.341300'); +addtime(date '2024-11-01', time '1 12:00:01.341300') +2024-11-02 12:00:01.341300 +select subtime(date '2024-11-01', time '1 12:00:01.341300'); +subtime(date '2024-11-01', time '1 12:00:01.341300') +2024-10-30 11:59:58.658700 +select addtime(date '2024-11-01', time '-1 12:00:01.341300'); +addtime(date '2024-11-01', time '-1 12:00:01.341300') +2024-10-30 11:59:58.658700 +select subtime(date '2024-11-01', time '-1 12:00:01.341300'); +subtime(date '2024-11-01', time '-1 12:00:01.341300') +2024-11-02 12:00:01.341300 +select addtime(col0, '12:00:01.341300') from t order by col0, col1 asc; +addtime(col0, '12:00:01.341300') +NULL +1000-01-01 12:00:01.341300 +2020-11-01 12:00:01.341300 +2024-11-01 12:00:01.341300 +2024-11-01 12:00:01.341300 +2024-11-01 12:00:01.341300 +9999-12-31 12:00:01.341300 +select subtime(col0, '12:00:01.341300') from t order by col0, col1 asc; +subtime(col0, '12:00:01.341300') +NULL +0999-12-31 11:59:58.658700 +2020-10-31 11:59:58.658700 +2024-10-31 11:59:58.658700 +2024-10-31 11:59:58.658700 +2024-10-31 11:59:58.658700 +9999-12-30 11:59:58.658700 +select addtime(col0, '1 12:00:01.341300') from t order by col0, col1 asc; +addtime(col0, '1 12:00:01.341300') +NULL +1000-01-02 12:00:01.341300 +2020-11-02 12:00:01.341300 +2024-11-02 12:00:01.341300 +2024-11-02 12:00:01.341300 +2024-11-02 12:00:01.341300 +NULL +select subtime(col0, '1 12:00:01.341300') from t order by col0, col1 asc; +subtime(col0, '1 12:00:01.341300') +NULL +0999-12-30 11:59:58.658700 +2020-10-30 11:59:58.658700 +2024-10-30 11:59:58.658700 +2024-10-30 11:59:58.658700 +2024-10-30 11:59:58.658700 +9999-12-29 11:59:58.658700 +select addtime(col0, '-1 12:00:01.341300') from t order by col0, col1 asc; +addtime(col0, '-1 12:00:01.341300') +NULL +0999-12-30 11:59:58.658700 +2020-10-30 11:59:58.658700 +2024-10-30 11:59:58.658700 +2024-10-30 11:59:58.658700 +2024-10-30 11:59:58.658700 +9999-12-29 11:59:58.658700 +select subtime(col0, '-1 12:00:01.341300') from t order by col0, col1 asc; +subtime(col0, '-1 12:00:01.341300') +NULL +1000-01-02 12:00:01.341300 +2020-11-02 12:00:01.341300 +2024-11-02 12:00:01.341300 +2024-11-02 12:00:01.341300 +2024-11-02 12:00:01.341300 +NULL +select addtime(col0, time '12:00:01.341300') from t order by col0, col1 asc; +addtime(col0, time '12:00:01.341300') +NULL +1000-01-01 12:00:01.341300 +2020-11-01 12:00:01.341300 +2024-11-01 12:00:01.341300 +2024-11-01 12:00:01.341300 +2024-11-01 12:00:01.341300 +9999-12-31 12:00:01.341300 +select subtime(col0, time '12:00:01.341300') from t order by col0, col1 asc; +subtime(col0, time '12:00:01.341300') +NULL +0999-12-31 11:59:58.658700 +2020-10-31 11:59:58.658700 +2024-10-31 11:59:58.658700 +2024-10-31 11:59:58.658700 +2024-10-31 11:59:58.658700 +9999-12-30 11:59:58.658700 +select addtime(col0, time '1 12:00:01.341300') from t order by col0, col1 asc; +addtime(col0, time '1 12:00:01.341300') +NULL +1000-01-02 12:00:01.341300 +2020-11-02 12:00:01.341300 +2024-11-02 12:00:01.341300 +2024-11-02 12:00:01.341300 +2024-11-02 12:00:01.341300 +NULL +select subtime(col0, time '1 12:00:01.341300') from t order by col0, col1 asc; +subtime(col0, time '1 12:00:01.341300') +NULL +0999-12-30 11:59:58.658700 +2020-10-30 11:59:58.658700 +2024-10-30 11:59:58.658700 +2024-10-30 11:59:58.658700 +2024-10-30 11:59:58.658700 +9999-12-29 11:59:58.658700 +select addtime(col0, time '-1 12:00:01.341300') from t order by col0, col1 asc; +addtime(col0, time '-1 12:00:01.341300') +NULL +0999-12-30 11:59:58.658700 +2020-10-30 11:59:58.658700 +2024-10-30 11:59:58.658700 +2024-10-30 11:59:58.658700 +2024-10-30 11:59:58.658700 +9999-12-29 11:59:58.658700 +select subtime(col0, time '-1 12:00:01.341300') from t order by col0, col1 asc; +subtime(col0, time '-1 12:00:01.341300') +NULL +1000-01-02 12:00:01.341300 +2020-11-02 12:00:01.341300 +2024-11-02 12:00:01.341300 +2024-11-02 12:00:01.341300 +2024-11-02 12:00:01.341300 +NULL +select addtime(col0, col1) from t order by col0, col1 asc; +addtime(col0, col1) +NULL +1000-01-01 12:00:01 +NULL +2024-10-30 11:59:59 +2024-11-01 12:00:01 +2024-11-02 12:00:01 +9999-12-31 12:00:01 +select subtime(col0, col1) from t order by col0, col1 asc; +subtime(col0, col1) +NULL +0999-12-31 11:59:59 +NULL +2024-11-02 12:00:01 +2024-10-31 11:59:59 +2024-10-30 11:59:59 +9999-12-30 11:59:59 +select addtime(col0, col2) from t order by col0, col1 asc; +addtime(col0, col2) +NULL +1000-01-01 12:00:01.341300 +NULL +2024-10-30 11:59:58.658700 +2024-11-01 12:00:01.341300 +2024-11-02 12:00:01.341300 +9999-12-31 12:00:01.341300 +select subtime(col0, col2) from t order by col0, col1 asc; +subtime(col0, col2) +NULL +0999-12-31 11:59:58.658700 +NULL +2024-11-02 12:00:01.341300 +2024-10-31 11:59:58.658700 +2024-10-30 11:59:58.658700 +9999-12-30 11:59:58.658700 +select addtime(col0, null) from t order by col0, col1 asc; +addtime(col0, null) +NULL +NULL +NULL +NULL +NULL +NULL +NULL +select subtime(col0, null) from t order by col0, col1 asc; +subtime(col0, null) +NULL +NULL +NULL +NULL +NULL +NULL +NULL +select addtime(null, col1) from t order by col0, col1 asc; +addtime(null, col1) +NULL +NULL +NULL +NULL +NULL +NULL +NULL +select subtime(null, col1) from t order by col0, col1 asc; +subtime(null, col1) +NULL +NULL +NULL +NULL +NULL +NULL +NULL +select addtime(null, col2) from t order by col0, col1 asc; +addtime(null, col2) +NULL +NULL +NULL +NULL +NULL +NULL +NULL +select subtime(null, col2) from t order by col0, col1 asc; +subtime(null, col2) +NULL +NULL +NULL +NULL +NULL +NULL +NULL +set sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; +select addtime(date '0-0-0', '12:00:01.341300'); +addtime(date '0-0-0', '12:00:01.341300') +NULL +select addtime(date '0-0-0', time '12:00:01.341300'); +addtime(date '0-0-0', time '12:00:01.341300') +NULL +select addtime(date '0-0-0', '1 12:00:01.341300'); +addtime(date '0-0-0', '1 12:00:01.341300') +NULL +select addtime(date '0-0-0', time '1 12:00:01.341300'); +addtime(date '0-0-0', time '1 12:00:01.341300') +NULL +select subtime(date '0-0-0', '12:00:01.341300'); +subtime(date '0-0-0', '12:00:01.341300') +NULL +select subtime(date '0-0-0', time '12:00:01.341300'); +subtime(date '0-0-0', time '12:00:01.341300') +NULL +select subtime(date '0-0-0', '1 12:00:01.341300'); +subtime(date '0-0-0', '1 12:00:01.341300') +NULL +select subtime(date '0-0-0', time '1 12:00:01.341300'); +subtime(date '0-0-0', time '1 12:00:01.341300') +NULL +set sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; +drop table if exists t; +create table t(col0 date, col1 time, col2 varchar(30)); +insert into t values ('0-0-0', '1:1:1', '1:1:1'), ('0-0-0', '0:0:0', '0:0:0'), ('2024-0-1', '1:1:1', '1:1:1'), ('2020-1-1', '-1 1:1:1', '-1 1:1:1'), ('2024-1-0', '1:1:1', '1:1:1'), ('2024-0-1', '1:1:1', '1:1:1'); +set sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; +select addtime(col0, col1) from t order by col0, col1, col2 asc; +addtime(col0, col1) +NULL +NULL +2019-12-30 22:58:59 +2023-12-01 01:01:01 +2023-12-01 01:01:01 +2023-12-31 01:01:01 +select subtime(col0, col1) from t order by col0, col1, col2 asc; +subtime(col0, col1) +NULL +NULL +2020-01-02 01:01:01 +2023-11-30 22:58:59 +2023-11-30 22:58:59 +2023-12-30 22:58:59 +select addtime(col0, col2) from t order by col0, col1, col2 asc; +addtime(col0, col2) +NULL +NULL +2019-12-30 22:58:59 +2023-12-01 01:01:01 +2023-12-01 01:01:01 +2023-12-31 01:01:01 +select subtime(col0, col2) from t order by col0, col1, col2 asc; +subtime(col0, col2) +NULL +NULL +2020-01-02 01:01:01 +2023-11-30 22:58:59 +2023-11-30 22:58:59 +2023-12-30 22:58:59 +set sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; +select addtime(col0, col1) from t order by col0, col1, col2 asc; +addtime(col0, col1) +NULL +NULL +2019-12-30 22:58:59 +2023-12-01 01:01:01 +2023-12-01 01:01:01 +2023-12-31 01:01:01 +select subtime(col0, col1) from t order by col0, col1, col2 asc; +subtime(col0, col1) +NULL +NULL +2020-01-02 01:01:01 +2023-11-30 22:58:59 +2023-11-30 22:58:59 +2023-12-30 22:58:59 +select addtime(col0, col2) from t order by col0, col1, col2 asc; +addtime(col0, col2) +NULL +NULL +2019-12-30 22:58:59 +2023-12-01 01:01:01 +2023-12-01 01:01:01 +2023-12-31 01:01:01 +select subtime(col0, col2) from t order by col0, col1, col2 asc; +subtime(col0, col2) +NULL +NULL +2020-01-02 01:01:01 +2023-11-30 22:58:59 +2023-11-30 22:58:59 +2023-12-30 22:58:59 +set sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; +drop table if exists t; +create table t(col0 datetime, col1 time, col2 varchar(30)); +insert into t values ('0-0-0', '1:1:1', '1:1:1'), ('0-0-0', '0:0:0', '0:0:0'), ('2024-0-1', '1:1:1', '1:1:1'), ('2020-1-1', '-1 1:1:1', '-1 1:1:1'), ('2024-1-0', '1:1:1', '1:1:1'), ('2024-0-1', '1:1:1', '1:1:1'); +set sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; +select addtime(col0, col1) from t order by col0, col1, col2 asc; +addtime(col0, col1) +NULL +NULL +2019-12-30 22:58:59 +2023-12-01 01:01:01 +2023-12-01 01:01:01 +2023-12-31 01:01:01 +select subtime(col0, col1) from t order by col0, col1, col2 asc; +subtime(col0, col1) +NULL +NULL +2020-01-02 01:01:01 +2023-11-30 22:58:59 +2023-11-30 22:58:59 +2023-12-30 22:58:59 +select addtime(col0, col2) from t order by col0, col1, col2 asc; +addtime(col0, col2) +NULL +NULL +2019-12-30 22:58:59 +2023-12-01 01:01:01 +2023-12-01 01:01:01 +2023-12-31 01:01:01 +select subtime(col0, col2) from t order by col0, col1, col2 asc; +subtime(col0, col2) +NULL +NULL +2020-01-02 01:01:01 +2023-11-30 22:58:59 +2023-11-30 22:58:59 +2023-12-30 22:58:59 +set sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; +select addtime(col0, col1) from t order by col0, col1, col2 asc; +addtime(col0, col1) +NULL +NULL +2019-12-30 22:58:59 +2023-12-01 01:01:01 +2023-12-01 01:01:01 +2023-12-31 01:01:01 +select subtime(col0, col1) from t order by col0, col1, col2 asc; +subtime(col0, col1) +NULL +NULL +2020-01-02 01:01:01 +2023-11-30 22:58:59 +2023-11-30 22:58:59 +2023-12-30 22:58:59 +select addtime(col0, col2) from t order by col0, col1, col2 asc; +addtime(col0, col2) +NULL +NULL +2019-12-30 22:58:59 +2023-12-01 01:01:01 +2023-12-01 01:01:01 +2023-12-31 01:01:01 +select subtime(col0, col2) from t order by col0, col1, col2 asc; +subtime(col0, col2) +NULL +NULL +2020-01-02 01:01:01 +2023-11-30 22:58:59 +2023-11-30 22:58:59 +2023-12-30 22:58:59 diff --git a/tests/integrationtest/t/expression/time.test b/tests/integrationtest/t/expression/time.test index 50efbebbba102..e7c96f3a8ff30 100644 --- a/tests/integrationtest/t/expression/time.test +++ b/tests/integrationtest/t/expression/time.test @@ -326,3 +326,81 @@ insert into t2 values('18446744073709551616', "1000-01-01 00:00:00" + INTERVAL insert into t2 values('-9223372036854775809', "1000-01-01 00:00:00" + INTERVAL -9223372036854775809 YEAR); select a, d from t2 order by a ASC; drop table if exists t1; + +drop table if exists t; +create table t(col0 date, col1 time, col2 varchar(30)); +insert into t values('2024-11-01', '12:00:01.341300', '12:00:01.341300'), ('2024-11-01', '1 12:00:01.341300', '1 12:00:01.341300'), ('2024-11-01', '-1 12:00:01.341300', '-1 12:00:01.341300'),('1000-01-01', '12:00:01.341300', '12:00:01.341300'), ('9999-12-31', '12:00:01.341300', '12:00:01.341300'), (null, '12:00:01.341300', '12:00:01.341300'), ('2020-11-01', null, null); +select addtime(date '2024-11-01', '12:00:01.341300'); +select subtime(date '2024-11-01', '12:00:01.341300'); +select addtime(date '2024-11-01', '1 12:00:01.341300'); +select subtime(date '2024-11-01', '1 12:00:01.341300'); +select addtime(date '2024-11-01', '-1 12:00:01.341300'); +select subtime(date '2024-11-01', '-1 12:00:01.341300'); +select addtime(date '2024-11-01', time '12:00:01.341300'); +select subtime(date '2024-11-01', time '12:00:01.341300'); +select addtime(date '2024-11-01', time '1 12:00:01.341300'); +select subtime(date '2024-11-01', time '1 12:00:01.341300'); +select addtime(date '2024-11-01', time '-1 12:00:01.341300'); +select subtime(date '2024-11-01', time '-1 12:00:01.341300'); +select addtime(col0, '12:00:01.341300') from t order by col0, col1 asc; +select subtime(col0, '12:00:01.341300') from t order by col0, col1 asc; +select addtime(col0, '1 12:00:01.341300') from t order by col0, col1 asc; +select subtime(col0, '1 12:00:01.341300') from t order by col0, col1 asc; +select addtime(col0, '-1 12:00:01.341300') from t order by col0, col1 asc; +select subtime(col0, '-1 12:00:01.341300') from t order by col0, col1 asc; +select addtime(col0, time '12:00:01.341300') from t order by col0, col1 asc; +select subtime(col0, time '12:00:01.341300') from t order by col0, col1 asc; +select addtime(col0, time '1 12:00:01.341300') from t order by col0, col1 asc; +select subtime(col0, time '1 12:00:01.341300') from t order by col0, col1 asc; +select addtime(col0, time '-1 12:00:01.341300') from t order by col0, col1 asc; +select subtime(col0, time '-1 12:00:01.341300') from t order by col0, col1 asc; +select addtime(col0, col1) from t order by col0, col1 asc; +select subtime(col0, col1) from t order by col0, col1 asc; +select addtime(col0, col2) from t order by col0, col1 asc; +select subtime(col0, col2) from t order by col0, col1 asc; +select addtime(col0, null) from t order by col0, col1 asc; +select subtime(col0, null) from t order by col0, col1 asc; +select addtime(null, col1) from t order by col0, col1 asc; +select subtime(null, col1) from t order by col0, col1 asc; +select addtime(null, col2) from t order by col0, col1 asc; +select subtime(null, col2) from t order by col0, col1 asc; + +set sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; +select addtime(date '0-0-0', '12:00:01.341300'); +select addtime(date '0-0-0', time '12:00:01.341300'); +select addtime(date '0-0-0', '1 12:00:01.341300'); +select addtime(date '0-0-0', time '1 12:00:01.341300'); +select subtime(date '0-0-0', '12:00:01.341300'); +select subtime(date '0-0-0', time '12:00:01.341300'); +select subtime(date '0-0-0', '1 12:00:01.341300'); +select subtime(date '0-0-0', time '1 12:00:01.341300'); + +set sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; +drop table if exists t; +create table t(col0 date, col1 time, col2 varchar(30)); +insert into t values ('0-0-0', '1:1:1', '1:1:1'), ('0-0-0', '0:0:0', '0:0:0'), ('2024-0-1', '1:1:1', '1:1:1'), ('2020-1-1', '-1 1:1:1', '-1 1:1:1'), ('2024-1-0', '1:1:1', '1:1:1'), ('2024-0-1', '1:1:1', '1:1:1'); +set sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; +select addtime(col0, col1) from t order by col0, col1, col2 asc; +select subtime(col0, col1) from t order by col0, col1, col2 asc; +select addtime(col0, col2) from t order by col0, col1, col2 asc; +select subtime(col0, col2) from t order by col0, col1, col2 asc; +set sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; +select addtime(col0, col1) from t order by col0, col1, col2 asc; +select subtime(col0, col1) from t order by col0, col1, col2 asc; +select addtime(col0, col2) from t order by col0, col1, col2 asc; +select subtime(col0, col2) from t order by col0, col1, col2 asc; + +set sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; +drop table if exists t; +create table t(col0 datetime, col1 time, col2 varchar(30)); +insert into t values ('0-0-0', '1:1:1', '1:1:1'), ('0-0-0', '0:0:0', '0:0:0'), ('2024-0-1', '1:1:1', '1:1:1'), ('2020-1-1', '-1 1:1:1', '-1 1:1:1'), ('2024-1-0', '1:1:1', '1:1:1'), ('2024-0-1', '1:1:1', '1:1:1'); +set sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; +select addtime(col0, col1) from t order by col0, col1, col2 asc; +select subtime(col0, col1) from t order by col0, col1, col2 asc; +select addtime(col0, col2) from t order by col0, col1, col2 asc; +select subtime(col0, col2) from t order by col0, col1, col2 asc; +set sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; +select addtime(col0, col1) from t order by col0, col1, col2 asc; +select subtime(col0, col1) from t order by col0, col1, col2 asc; +select addtime(col0, col2) from t order by col0, col1, col2 asc; +select subtime(col0, col2) from t order by col0, col1, col2 asc;