Skip to content

Commit 480bd62

Browse files
qw4990zz-jason
authored andcommitted
expression: fix issue that function dayname is incompatible with Mysql when doing arithmetic(#9975) (#10732)
1 parent 761228d commit 480bd62

File tree

4 files changed

+100
-6
lines changed

4 files changed

+100
-6
lines changed

expression/builtin_cast.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,6 +1688,23 @@ func (i inCastContext) String() string {
16881688
// @see BuildCastFunction4Union
16891689
const inUnionCastContext inCastContext = 0
16901690

1691+
// hasSpecialCast checks if this expr has its own special cast function.
1692+
// for example(#9713): when doing arithmetic using results of function DayName,
1693+
// "Monday" should be regarded as 0, "Tuesday" should be regarded as 1 and so on.
1694+
func hasSpecialCast(ctx sessionctx.Context, expr Expression, tp *types.FieldType) bool {
1695+
switch f := expr.(type) {
1696+
case *ScalarFunction:
1697+
switch f.FuncName.L {
1698+
case ast.DayName:
1699+
switch tp.EvalType() {
1700+
case types.ETInt, types.ETReal:
1701+
return true
1702+
}
1703+
}
1704+
}
1705+
return false
1706+
}
1707+
16911708
// BuildCastFunction4Union build a implicitly CAST ScalarFunction from the Union
16921709
// Expression.
16931710
func BuildCastFunction4Union(ctx sessionctx.Context, expr Expression, tp *types.FieldType) (res Expression) {
@@ -1700,6 +1717,10 @@ func BuildCastFunction4Union(ctx sessionctx.Context, expr Expression, tp *types.
17001717

17011718
// BuildCastFunction builds a CAST ScalarFunction from the Expression.
17021719
func BuildCastFunction(ctx sessionctx.Context, expr Expression, tp *types.FieldType) (res Expression) {
1720+
if hasSpecialCast(ctx, expr, tp) {
1721+
return expr
1722+
}
1723+
17031724
var fc functionClass
17041725
switch tp.EvalType() {
17051726
case types.ETInt:

expression/builtin_time.go

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,21 +1084,45 @@ func (b *builtinDayNameSig) Clone() builtinFunc {
10841084
return newSig
10851085
}
10861086

1087-
// evalString evals a builtinDayNameSig.
1088-
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_dayname
1089-
func (b *builtinDayNameSig) evalString(row chunk.Row) (string, bool, error) {
1087+
func (b *builtinDayNameSig) evalIndex(row chunk.Row) (int64, bool, error) {
10901088
arg, isNull, err := b.args[0].EvalTime(b.ctx, row)
10911089
if isNull || err != nil {
1092-
return "", isNull, errors.Trace(err)
1090+
return 0, isNull, err
10931091
}
10941092
if arg.InvalidZero() {
1095-
return "", true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenWithStackByArgs(arg.String())))
1093+
return 0, true, handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenWithStackByArgs(arg.String()))
10961094
}
10971095
// Monday is 0, ... Sunday = 6 in MySQL
10981096
// but in go, Sunday is 0, ... Saturday is 6
10991097
// w will do a conversion.
11001098
res := (int64(arg.Time.Weekday()) + 6) % 7
1101-
return types.WeekdayNames[res], false, nil
1099+
return res, false, nil
1100+
}
1101+
1102+
// evalString evals a builtinDayNameSig.
1103+
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_dayname
1104+
func (b *builtinDayNameSig) evalString(row chunk.Row) (string, bool, error) {
1105+
idx, isNull, err := b.evalIndex(row)
1106+
if isNull || err != nil {
1107+
return "", isNull, err
1108+
}
1109+
return types.WeekdayNames[idx], false, nil
1110+
}
1111+
1112+
func (b *builtinDayNameSig) evalReal(row chunk.Row) (float64, bool, error) {
1113+
idx, isNull, err := b.evalIndex(row)
1114+
if isNull || err != nil {
1115+
return 0, isNull, err
1116+
}
1117+
return float64(idx), false, nil
1118+
}
1119+
1120+
func (b *builtinDayNameSig) evalInt(row chunk.Row) (int64, bool, error) {
1121+
idx, isNull, err := b.evalIndex(row)
1122+
if isNull || err != nil {
1123+
return 0, isNull, err
1124+
}
1125+
return idx, false, nil
11021126
}
11031127

11041128
type dayOfMonthFunctionClass struct {

expression/function_traits.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ var unFoldableFunctions = map[string]struct{}{
5050
ast.SetVar: {},
5151
ast.GetVar: {},
5252
ast.GetParam: {},
53+
ast.DayName: {},
5354
}
5455

5556
// inequalFunctions stores functions which cannot be propagated from column equal condition.

expression/integration_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4107,3 +4107,51 @@ monthname(str_to_date(1, '%m')), monthname(str_to_date(0, '%m'));`).Check(testki
41074107
tk.MustQuery(nullCase.sql).Check(testkit.Rows(nullCase.ret))
41084108
}
41094109
}
4110+
4111+
func (s *testIntegrationSuite) TestDaynameArithmetic(c *C) {
4112+
tk := testkit.NewTestKit(c, s.store)
4113+
defer s.cleanEnv(c)
4114+
4115+
cases := []struct {
4116+
sql string
4117+
result string
4118+
}{
4119+
{`select dayname("1962-03-01")+0;`, "3"},
4120+
{`select dayname("1962-03-02")+0;`, "4"},
4121+
{`select dayname("1962-03-03")+0;`, "5"},
4122+
{`select dayname("1962-03-04")+0;`, "6"},
4123+
{`select dayname("1962-03-05")+0;`, "0"},
4124+
{`select dayname("1962-03-06")+0;`, "1"},
4125+
{`select dayname("1962-03-07")+0;`, "2"},
4126+
{`select dayname("1962-03-08")+0;`, "3"},
4127+
{`select dayname("1962-03-01")+1;`, "4"},
4128+
{`select dayname("1962-03-01")+2;`, "5"},
4129+
{`select dayname("1962-03-01")+3;`, "6"},
4130+
{`select dayname("1962-03-01")+4;`, "7"},
4131+
{`select dayname("1962-03-01")+5;`, "8"},
4132+
{`select dayname("1962-03-01")+6;`, "9"},
4133+
{`select dayname("1962-03-01")+7;`, "10"},
4134+
{`select dayname("1962-03-01")+2333;`, "2336"},
4135+
{`select dayname("1962-03-01")+2.333;`, "5.333"},
4136+
{`select dayname("1962-03-01")>2;`, "1"},
4137+
{`select dayname("1962-03-01")<2;`, "0"},
4138+
{`select dayname("1962-03-01")=3;`, "1"},
4139+
{`select dayname("1962-03-01")!=3;`, "0"},
4140+
{`select dayname("1962-03-01")<4;`, "1"},
4141+
{`select dayname("1962-03-01")>4;`, "0"},
4142+
{`select !dayname("1962-03-01");`, "0"},
4143+
{`select dayname("1962-03-01")&1;`, "1"},
4144+
{`select dayname("1962-03-01")&3;`, "3"},
4145+
{`select dayname("1962-03-01")&7;`, "3"},
4146+
{`select dayname("1962-03-01")|1;`, "3"},
4147+
{`select dayname("1962-03-01")|3;`, "3"},
4148+
{`select dayname("1962-03-01")|7;`, "7"},
4149+
{`select dayname("1962-03-01")^1;`, "2"},
4150+
{`select dayname("1962-03-01")^3;`, "0"},
4151+
{`select dayname("1962-03-01")^7;`, "4"},
4152+
}
4153+
4154+
for _, c := range cases {
4155+
tk.MustQuery(c.sql).Check(testkit.Rows(c.result))
4156+
}
4157+
}

0 commit comments

Comments
 (0)