From 12a9d5c682486a8c885c5c45d67e6f58f34e1f68 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Tue, 25 Jun 2024 15:09:55 +0200 Subject: [PATCH 1/8] Optimized EXTRACT( FROM ) for partition pruning. --- .../partition/partition_pruner_test.go | 23 +++++++++++++ pkg/planner/core/rule_partition_processor.go | 34 +++++++++++++++++-- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/pkg/planner/core/casetest/partition/partition_pruner_test.go b/pkg/planner/core/casetest/partition/partition_pruner_test.go index 23057c98fc896..1ba33d50e9df2 100644 --- a/pkg/planner/core/casetest/partition/partition_pruner_test.go +++ b/pkg/planner/core/casetest/partition/partition_pruner_test.go @@ -233,3 +233,26 @@ func TestPointGetIntHandleNotFirst(t *testing.T) { tk.MustQuery("select * from t WHERE a BETWEEN 13 AND 13").Check(testkit.Rows("1 13 1")) tk.MustQuery(`select * from t`).Check(testkit.Rows("1 13 1")) } + +func TestPruneExtractYear(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec(`create table t ( + a bigint not null, + b date not null, + c varchar(255), + primary key (a,b)) +PARTITION BY RANGE (EXTRACT(YEAR FROM b)) +(PARTITION p2019 VALUES LESS THAN (2020), + PARTITION p2020 VALUES LESS THAN (2021), + PARTITION p2021 VALUES LESS THAN (2022), + PARTITION p2022 VALUES LESS THAN (2023), + PARTITION p2023 VALUES LESS THAN (2024), + PARTITION p2024 VALUES LESS THAN (2025), + PARTITION pMax VALUES LESS THAN (MAXVALUE))`) + tk.MustExec(`insert into t values(1, '2021-01-01', "1,2020-12-31"),(2,'2020-12-31',"2,2020-12-31")`) + tk.MustExec(`analyze table t`) + rows := tk.MustQuery("explain format='brief' select * from t WHERE b = '2020-12-31'").Rows() + require.Equal(t, "partition:p2020", rows[0][3]) +} diff --git a/pkg/planner/core/rule_partition_processor.go b/pkg/planner/core/rule_partition_processor.go index 0350591926d9f..d41c4cee15d37 100644 --- a/pkg/planner/core/rule_partition_processor.go +++ b/pkg/planner/core/rule_partition_processor.go @@ -1065,9 +1065,11 @@ func makePartitionByFnCol(sctx base.PlanContext, columns []*expression.Column, n switch raw := partExpr.(type) { case *expression.ScalarFunction: args := raw.GetArgs() - // Special handle for floor(unix_timestamp(ts)) as partition expression. - // This pattern is so common for timestamp(3) column as partition expression that it deserve an optimization. - if raw.FuncName.L == ast.Floor { + // Optimizations for a limited set of functions + switch raw.FuncName.L { + case ast.Floor: + // Special handle for floor(unix_timestamp(ts)) as partition expression. + // This pattern is so common for timestamp(3) column as partition expression that it deserve an optimization. if ut, ok := args[0].(*expression.ScalarFunction); ok && ut.FuncName.L == ast.UnixTimestamp { args1 := ut.GetArgs() if len(args1) == 1 { @@ -1076,6 +1078,28 @@ func makePartitionByFnCol(sctx base.PlanContext, columns []*expression.Column, n } } } + case ast.Extract: + con, ok := args[0].(*expression.Constant) + if !ok { + break + } + col, ok = args[1].(*expression.Column) + if !ok { + break + } + // TODO: should we check for timestamp, since that may have time zone conversions? + val := strings.ToUpper(con.String()) + switch val { + // WEEK is not included, since it may use default_week_format in the future! + case "DAY", "MONTH", "QUARTER", "YEAR", "DAY_MICROSECOND", "DAY_SECOND", "DAY_MINUTE", "DAY_HOUR", "YEAR_MONTH": + // TODO: we could check the type+fsp in the column definition + // to see if Strict monotone for DAY, DAY_MICROSECOND, DAY_SECOND + // Note, this function will not have the column as first argument, + // so in replaceColumnWithConst it will replace the second argument, which + // is special handling there too! + return col, raw, monotoneModeNonStrict, nil + } + } fn = raw @@ -1551,6 +1575,10 @@ func replaceColumnWithConst(partFn *expression.ScalarFunction, con *expression.C return partFn } } + if partFn.FuncName.L == ast.Extract { + args[1] = con + return partFn + } // No 'copy on write' for the expression here, this is a dangerous operation. args[0] = con From ea64f4f9d8b19e9146e067215d3dc0a2c5b357ca Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Tue, 25 Jun 2024 15:23:54 +0200 Subject: [PATCH 2/8] linting --- pkg/planner/core/rule_partition_processor.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/planner/core/rule_partition_processor.go b/pkg/planner/core/rule_partition_processor.go index d41c4cee15d37..070ed06c88f8e 100644 --- a/pkg/planner/core/rule_partition_processor.go +++ b/pkg/planner/core/rule_partition_processor.go @@ -1099,7 +1099,6 @@ func makePartitionByFnCol(sctx base.PlanContext, columns []*expression.Column, n // is special handling there too! return col, raw, monotoneModeNonStrict, nil } - } fn = raw From 1579e08f497a24aa79e5aa6fe627a7d93e9f417a Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Tue, 25 Jun 2024 15:27:57 +0200 Subject: [PATCH 3/8] bazel_prepare --- pkg/planner/core/casetest/partition/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/planner/core/casetest/partition/BUILD.bazel b/pkg/planner/core/casetest/partition/BUILD.bazel index 70e2eb3e0b055..4946b61feeb6f 100644 --- a/pkg/planner/core/casetest/partition/BUILD.bazel +++ b/pkg/planner/core/casetest/partition/BUILD.bazel @@ -10,7 +10,7 @@ go_test( ], data = glob(["testdata/**"]), flaky = True, - shard_count = 7, + shard_count = 8, deps = [ "//pkg/config", "//pkg/planner/util/coretestsdk", From 3c7f0764209b074f6f07a64e60e05f4ae9be0be4 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Tue, 9 Jul 2024 14:25:14 +0200 Subject: [PATCH 4/8] Added more extensive tests. --- pkg/ddl/partition.go | 1 + .../core/casetest/partition/BUILD.bazel | 2 +- .../partition/partition_pruner_test.go | 292 ++++++++++++++++++ pkg/planner/core/rule_partition_processor.go | 60 +++- pkg/testkit/testkit.go | 2 +- 5 files changed, 344 insertions(+), 13 deletions(-) diff --git a/pkg/ddl/partition.go b/pkg/ddl/partition.go index 55ef0d59b624c..657537b725631 100644 --- a/pkg/ddl/partition.go +++ b/pkg/ddl/partition.go @@ -4425,6 +4425,7 @@ func collectArgsType(tblInfo *model.TableInfo, exprs ...ast.ExprNode) ([]byte, e } func hasDateArgs(argsType ...byte) bool { + // Should it be slice.AllOf ? return slice.AnyOf(argsType, func(i int) bool { return argsType[i] == mysql.TypeDate || argsType[i] == mysql.TypeDatetime }) diff --git a/pkg/planner/core/casetest/partition/BUILD.bazel b/pkg/planner/core/casetest/partition/BUILD.bazel index 4946b61feeb6f..571ae2469b6d0 100644 --- a/pkg/planner/core/casetest/partition/BUILD.bazel +++ b/pkg/planner/core/casetest/partition/BUILD.bazel @@ -10,7 +10,7 @@ go_test( ], data = glob(["testdata/**"]), flaky = True, - shard_count = 8, + shard_count = 10, deps = [ "//pkg/config", "//pkg/planner/util/coretestsdk", diff --git a/pkg/planner/core/casetest/partition/partition_pruner_test.go b/pkg/planner/core/casetest/partition/partition_pruner_test.go index 1ba33d50e9df2..9299584591dc2 100644 --- a/pkg/planner/core/casetest/partition/partition_pruner_test.go +++ b/pkg/planner/core/casetest/partition/partition_pruner_test.go @@ -18,6 +18,7 @@ import ( "bytes" "fmt" "sort" + "strconv" "strings" "testing" @@ -256,3 +257,294 @@ PARTITION BY RANGE (EXTRACT(YEAR FROM b)) rows := tk.MustQuery("explain format='brief' select * from t WHERE b = '2020-12-31'").Rows() require.Equal(t, "partition:p2020", rows[0][3]) } + +type ExtractTestCase struct { + TimeUnit string + ColumnTypes []string + PruneResult []string // cmpOps + BETWEEN pRange[1] [, pRange[2]] + NoFspResult string +} + +// TODO: test LIST/HASH pruning? +func TestRangeDatePruningExtract(t *testing.T) { + for _, colType := range []string{"DATE", "DATETIME", "DATETIME(1)", "DATETIME(6)"} { + extractTestCases := []ExtractTestCase{ + { + "YEAR", + []string{"DATE", "DATETIME"}, + []string{"p2", "p0,p1,p2", "p2,p3,pMax", "p0,p1,p2", "p2,p3,pMax", "p2,p3"}, + "", + }, { + "QUARTER", + []string{"DATE", "DATETIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, { + "YEAR_MONTH", + []string{"DATE", "DATETIME"}, + []string{"p2", "p0,p1,p2", "p2,p3,pMax", "p0,p1,p2", "p2,p3,pMax", "p2,p3"}, + "", + }, { + + "MONTH", + []string{"DATE", "DATETIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, { + "WEEK", + []string{}, + []string{}, + "", + }, { + "DAY", + []string{"DATE", "DATETIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, { + "DAY_HOUR", + []string{"DATETIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, { + "DAY_MINUTE", + []string{"DATETIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, { + "DAY_SECOND", + []string{"DATETIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, { + "DAY_MICROSECOND", + []string{"DATETIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + // Would also be affected by FSP truncation, but since the partition definitions + // in this test are increasing for each partition, this will not be noticed + "", + }, { + "HOUR", + []string{"DATETIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, { + "HOUR_MINUTE", + []string{"DATETIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, { + "HOUR_SECOND", + []string{"DATETIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, { + "HOUR_MICROSECOND", + []string{"DATETIME"}, + // If no fsp is given, the partitioning expression still records + // the fsp, but evaluation will truncate it, so that is why + // the pruning will give p1, which is actually correct! + []string{"p2", "all", "all", "all", "all", "all"}, + "p1", + }, { + "MINUTE", + []string{"DATETIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, { + "MINUTE_SECOND", + []string{"DATETIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, { + "MINUTE_MICROSECOND", + []string{"DATETIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "p1", + }, { + "SECOND", + []string{"DATETIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, { + "SECOND_MICROSECOND", + []string{"DATETIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "p1", + }, { + "MICROSECOND", + []string{"DATETIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "p1", + }, + } + runExtractTestCases(t, colType, extractTestCases) + } +} + +func runExtractTestCases(t *testing.T, colType string, extractTestCases []ExtractTestCase) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + + // Loop over different datatypes, DATE, DATETIME(fsp), TIMESTAMP(fsp) + pRanges := []string{ + "1990-01-01 00:00:00.000000", + "1991-04-02 01:01:01.100000", + "1992-08-03 02:02:02.200000", + "1993-12-31 23:59:59.999999", + } + cmpOps := []string{"=", "<", ">", "<=", ">="} + for _, tc := range extractTestCases { + found := false + hasFsp := strings.HasSuffix(colType, ")") + for _, cType := range tc.ColumnTypes { + end := strings.TrimPrefix(colType, cType) + + if end == "" || end[:1] == "(" { + found = true + } + } + pRangesStrings := make([]string, 0, len(pRanges)) + partDefs := "" + for i, pString := range pRanges { + r := tk.MustQuery(`SELECT EXTRACT(` + tc.TimeUnit + ` FROM '` + pString + `')`) + pRangesStrings = append(pRangesStrings, r.Rows()[0][0].(string)) + if i > 0 { + partDefs += ", " + } + partDefs += "PARTITION p" + + strconv.Itoa(i) + + " VALUES LESS THAN (" + + pRangesStrings[i] + ")" + } + tk.MustExec(`drop table if exists t`) + createSQL := `create table t (d ` + colType + `, f varchar(255)) partition by range (EXTRACT(` + tc.TimeUnit + ` FROM d)) (` + partDefs + `, partition pMax values less than (maxvalue))` + if !found { + tk.MustContainErrMsg(createSQL, `[ddl:1486]Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed`) + continue + } + tk.MustExec(createSQL) + for i, op := range cmpOps { + res := tk.MustQuery(`explain select * from t where d ` + op + ` '` + pRanges[1] + `'`) + parts := strings.TrimPrefix(res.Rows()[0][3].(string), "partition:") + require.Greater(t, len(tc.PruneResult), i, "PruneResults does not include enough values, colType %s, EXTRACT %s, op %s", colType, tc.TimeUnit, op) + expects := tc.PruneResult[i] + if i == 0 && !hasFsp && tc.NoFspResult != "" { + expects = tc.NoFspResult + } + require.Equal(t, expects, parts, "colType %s, EXTRACT %s, op %s", colType, tc.TimeUnit, op) + } + res := tk.MustQuery(`explain select * from t where d between '` + pRanges[1] + `' and '` + pRanges[2] + `'`) + parts := strings.TrimPrefix(res.Rows()[0][3].(string), "partition:") + require.Equal(t, tc.PruneResult[len(cmpOps)], parts, "colType %s, EXTRACT %s, BETWEEN", colType, tc.TimeUnit) + } +} + +func TestRangeTimePruningExtract(t *testing.T) { + for _, colType := range []string{"TIME", "TIME(1)", "TIME(6)", "TIMESTAMP", "TIMESTAMP(1)", "TIMESTAMP(6)"} { + extractTestCases := []ExtractTestCase{ + { + "YEAR", + []string{"DATE", "DATETIME"}, + []string{}, + "", + }, { + "QUARTER", + []string{"DATE", "DATETIME"}, + []string{}, + "", + }, { + "YEAR_MONTH", + []string{"DATE", "DATETIME"}, + []string{}, + "", + }, { + "MONTH", + []string{"DATE", "DATETIME"}, + []string{}, + "", + }, { + "WEEK", + []string{"DATE", "DATETIME"}, + []string{}, + "", + }, { + "DAY", + []string{"DATE", "DATETIME"}, + []string{}, + "", + }, { + "DAY_HOUR", + []string{"DATETIME"}, + []string{}, + "", + }, { + "DAY_MINUTE", + []string{"DATETIME"}, + []string{}, + "", + }, { + "DAY_SECOND", + []string{"DATETIME"}, + []string{}, + "", + }, { + "DAY_MICROSECOND", + []string{"DATETIME"}, + []string{}, + "", + }, { + "HOUR", + []string{"TIME"}, + []string{"p2", "p0,p1,p2", "p2,p3,pMax", "p0,p1,p2", "p2,p3,pMax", "p2,p3"}, + "", + }, { + "HOUR_MINUTE", + []string{"TIME"}, + []string{"p2", "p0,p1,p2", "p2,p3,pMax", "p0,p1,p2", "p2,p3,pMax", "p2,p3"}, + "", + }, { + "HOUR_SECOND", + []string{"TIME"}, + []string{"p2", "p0,p1,p2", "p2,p3,pMax", "p0,p1,p2", "p2,p3,pMax", "p2,p3"}, + "", + }, { + "HOUR_MICROSECOND", + []string{"TIME"}, + []string{"p2", "p0,p1,p2", "p2,p3,pMax", "p0,p1,p2", "p2,p3,pMax", "p2,p3"}, + "", + }, { + "MINUTE", + []string{"TIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, { + "MINUTE_SECOND", + []string{"TIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, { + "MINUTE_MICROSECOND", + []string{"TIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, { + "SECOND", + []string{"TIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, { + "SECOND_MICROSECOND", + []string{"TIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, { + "MICROSECOND", + []string{"TIME"}, + []string{"p2", "all", "all", "all", "all", "all"}, + "", + }, + } + runExtractTestCases(t, colType, extractTestCases) + } +} diff --git a/pkg/planner/core/rule_partition_processor.go b/pkg/planner/core/rule_partition_processor.go index be9a2963cbf5b..60a53f4e9acf6 100644 --- a/pkg/planner/core/rule_partition_processor.go +++ b/pkg/planner/core/rule_partition_processor.go @@ -19,6 +19,7 @@ import ( "cmp" "context" "fmt" + "github.com/pingcap/tipb/go-tipb" "math" "slices" "sort" @@ -1087,19 +1088,50 @@ func makePartitionByFnCol(sctx base.PlanContext, columns []*expression.Column, n } col, ok = args[1].(*expression.Column) if !ok { + // Special case where CastTimeToDuration is added + expr, ok := args[1].(*expression.ScalarFunction) + if !ok { + break + } + if expr.Function.PbCode() != tipb.ScalarFuncSig_CastTimeAsDuration { + break + } + castArgs := expr.GetArgs() + col, ok = castArgs[0].(*expression.Column) + if !ok { + break + } + } + if con.Value.Kind() != types.KindString { break } - // TODO: should we check for timestamp, since that may have time zone conversions? - val := strings.ToUpper(con.String()) - switch val { - // WEEK is not included, since it may use default_week_format in the future! - case "DAY", "MONTH", "QUARTER", "YEAR", "DAY_MICROSECOND", "DAY_SECOND", "DAY_MINUTE", "DAY_HOUR", "YEAR_MONTH": - // TODO: we could check the type+fsp in the column definition - // to see if Strict monotone for DAY, DAY_MICROSECOND, DAY_SECOND - // Note, this function will not have the column as first argument, - // so in replaceColumnWithConst it will replace the second argument, which - // is special handling there too! - return col, raw, monotoneModeNonStrict, nil + val := con.Value.GetString() + colType := col.GetStaticType().GetType() + switch colType { + case mysql.TypeDate, mysql.TypeDatetime: + switch val { + // Only YEAR, YEAR_MONTH can be considered monotonic, the rest will wrap around! + case "YEAR", "YEAR_MONTH": + // Note, this function will not have the column as first argument, + // so in replaceColumnWithConst it will replace the second argument, which + // is special handling there too! + return col, raw, monotoneModeNonStrict, nil + default: + return col, raw, monotonous, nil + } + case mysql.TypeDuration: + switch val { + // Only HOUR* can be considered monotonic, the rest will wrap around! + // TODO: if fsp match for HOUR_SECOND or HOUR_MICROSECOND we could + // mark it as monotoneModeStrict + case "HOUR", "HOUR_MINUTE", "HOUR_SECOND", "HOUR_MICROSECOND": + // Note, this function will not have the column as first argument, + // so in replaceColumnWithConst it will replace the second argument, which + // is special handling there too! + return col, raw, monotoneModeNonStrict, nil + default: + return col, raw, monotonous, nil + } } } @@ -1577,6 +1609,12 @@ func replaceColumnWithConst(partFn *expression.ScalarFunction, con *expression.C } } if partFn.FuncName.L == ast.Extract { + if expr, ok := args[1].(*expression.ScalarFunction); ok && expr.Function.PbCode() == tipb.ScalarFuncSig_CastTimeAsDuration { + // Special handing if Cast is added + funcArgs := expr.GetArgs() + funcArgs[0] = con + return partFn + } args[1] = con return partFn } diff --git a/pkg/testkit/testkit.go b/pkg/testkit/testkit.go index a7dfd85443fc0..fbfd9d8855d6a 100644 --- a/pkg/testkit/testkit.go +++ b/pkg/testkit/testkit.go @@ -485,7 +485,7 @@ func (tk *TestKit) MustGetDBError(sql string, dberr *terror.Error) { // MustContainErrMsg executes a sql statement and assert its error message containing errStr. func (tk *TestKit) MustContainErrMsg(sql string, errStr any) { err := tk.ExecToErr(sql) - tk.require.Error(err) + tk.require.Error(err, "sql: %s", sql) tk.require.Contains(err.Error(), errStr) } From 6d459cb0cc89a167945423cc98c51f66f209908a Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Tue, 9 Jul 2024 14:33:20 +0200 Subject: [PATCH 5/8] Linting --- pkg/planner/core/rule_partition_processor.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/planner/core/rule_partition_processor.go b/pkg/planner/core/rule_partition_processor.go index 60a53f4e9acf6..9360b96211087 100644 --- a/pkg/planner/core/rule_partition_processor.go +++ b/pkg/planner/core/rule_partition_processor.go @@ -19,7 +19,6 @@ import ( "cmp" "context" "fmt" - "github.com/pingcap/tipb/go-tipb" "math" "slices" "sort" @@ -43,6 +42,7 @@ import ( "github.com/pingcap/tidb/pkg/util/plancodec" "github.com/pingcap/tidb/pkg/util/ranger" "github.com/pingcap/tidb/pkg/util/set" + "github.com/pingcap/tipb/go-tipb" ) // FullRange represent used all partitions. From dc347a6c193abbc4f8eb950ea15bf8401f7f08e9 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Tue, 9 Jul 2024 16:09:27 +0200 Subject: [PATCH 6/8] Removed comment --- pkg/ddl/partition.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/ddl/partition.go b/pkg/ddl/partition.go index 657537b725631..55ef0d59b624c 100644 --- a/pkg/ddl/partition.go +++ b/pkg/ddl/partition.go @@ -4425,7 +4425,6 @@ func collectArgsType(tblInfo *model.TableInfo, exprs ...ast.ExprNode) ([]byte, e } func hasDateArgs(argsType ...byte) bool { - // Should it be slice.AllOf ? return slice.AnyOf(argsType, func(i int) bool { return argsType[i] == mysql.TypeDate || argsType[i] == mysql.TypeDatetime }) From 57d3d66c340fe1608fbde5b86d850de67d9e1dd5 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Wed, 10 Jul 2024 10:55:12 +0200 Subject: [PATCH 7/8] Update pkg/planner/core/rule_partition_processor.go Co-authored-by: Hangjie Mo --- pkg/planner/core/rule_partition_processor.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/planner/core/rule_partition_processor.go b/pkg/planner/core/rule_partition_processor.go index 9360b96211087..d36c3f91e0f6a 100644 --- a/pkg/planner/core/rule_partition_processor.go +++ b/pkg/planner/core/rule_partition_processor.go @@ -1607,8 +1607,7 @@ func replaceColumnWithConst(partFn *expression.ScalarFunction, con *expression.C args[0] = con return partFn } - } - if partFn.FuncName.L == ast.Extract { + } else if partFn.FuncName.L == ast.Extract { if expr, ok := args[1].(*expression.ScalarFunction); ok && expr.Function.PbCode() == tipb.ScalarFuncSig_CastTimeAsDuration { // Special handing if Cast is added funcArgs := expr.GetArgs() From 3ab5cb1b335d857b5289826a86e8861bd993e3ed Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Wed, 10 Jul 2024 11:02:27 +0200 Subject: [PATCH 8/8] Removed duplicate test --- .../core/casetest/partition/BUILD.bazel | 2 +- .../partition/partition_pruner_test.go | 23 ------------------- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/pkg/planner/core/casetest/partition/BUILD.bazel b/pkg/planner/core/casetest/partition/BUILD.bazel index 571ae2469b6d0..b372c30815a03 100644 --- a/pkg/planner/core/casetest/partition/BUILD.bazel +++ b/pkg/planner/core/casetest/partition/BUILD.bazel @@ -10,7 +10,7 @@ go_test( ], data = glob(["testdata/**"]), flaky = True, - shard_count = 10, + shard_count = 9, deps = [ "//pkg/config", "//pkg/planner/util/coretestsdk", diff --git a/pkg/planner/core/casetest/partition/partition_pruner_test.go b/pkg/planner/core/casetest/partition/partition_pruner_test.go index 9299584591dc2..78d54174f0773 100644 --- a/pkg/planner/core/casetest/partition/partition_pruner_test.go +++ b/pkg/planner/core/casetest/partition/partition_pruner_test.go @@ -235,29 +235,6 @@ func TestPointGetIntHandleNotFirst(t *testing.T) { tk.MustQuery(`select * from t`).Check(testkit.Rows("1 13 1")) } -func TestPruneExtractYear(t *testing.T) { - store := testkit.CreateMockStore(t) - tk := testkit.NewTestKit(t, store) - tk.MustExec("use test") - tk.MustExec(`create table t ( - a bigint not null, - b date not null, - c varchar(255), - primary key (a,b)) -PARTITION BY RANGE (EXTRACT(YEAR FROM b)) -(PARTITION p2019 VALUES LESS THAN (2020), - PARTITION p2020 VALUES LESS THAN (2021), - PARTITION p2021 VALUES LESS THAN (2022), - PARTITION p2022 VALUES LESS THAN (2023), - PARTITION p2023 VALUES LESS THAN (2024), - PARTITION p2024 VALUES LESS THAN (2025), - PARTITION pMax VALUES LESS THAN (MAXVALUE))`) - tk.MustExec(`insert into t values(1, '2021-01-01', "1,2020-12-31"),(2,'2020-12-31',"2,2020-12-31")`) - tk.MustExec(`analyze table t`) - rows := tk.MustQuery("explain format='brief' select * from t WHERE b = '2020-12-31'").Rows() - require.Equal(t, "partition:p2020", rows[0][3]) -} - type ExtractTestCase struct { TimeUnit string ColumnTypes []string