From 83bef61797c8ea1d0ca91953db56c59924487bd6 Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Thu, 6 Jun 2024 16:19:26 +0800 Subject: [PATCH] planner: fix panic error when subquery + always true predicate in where clause (#53525) (#53813) close pingcap/tidb#46962 --- planner/core/physical_plan_test.go | 26 ++++++++++++++++ planner/core/rule_build_key_info.go | 6 +++- planner/core/testdata/plan_suite_in.json | 8 +++++ planner/core/testdata/plan_suite_out.json | 38 +++++++++++++++++++++++ 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/planner/core/physical_plan_test.go b/planner/core/physical_plan_test.go index ea2e05ae99e7d..190142e04371d 100644 --- a/planner/core/physical_plan_test.go +++ b/planner/core/physical_plan_test.go @@ -2588,3 +2588,29 @@ func TestIssues49377Plan(t *testing.T) { tk.MustQuery("explain format = 'brief' " + ts).Check(testkit.Rows(output[i].Plan...)) } } + +// Test issue #46962 plan +func TestAlwaysTruePredicateWithSubquery(t *testing.T) { + var ( + input []string + output []struct { + SQL string + Plan []string + Warning []string + } + ) + planSuiteData := core.GetPlanSuiteData() + planSuiteData.LoadTestCases(t, &input, &output) + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + + tk.MustExec("use test") + tk.MustExec(`CREATE TABLE t ( a int NOT NULL , b int NOT NULL ) `) + for i, ts := range input { + testdata.OnRecord(func() { + output[i].SQL = ts + output[i].Plan = testdata.ConvertRowsToStrings(tk.MustQuery(ts).Rows()) + }) + tk.MustQuery(ts).Check(testkit.Rows(output[i].Plan...)) + } +} diff --git a/planner/core/rule_build_key_info.go b/planner/core/rule_build_key_info.go index 5b2f5c4ad4580..abfeb7935d05b 100644 --- a/planner/core/rule_build_key_info.go +++ b/planner/core/rule_build_key_info.go @@ -44,7 +44,11 @@ func buildKeyInfo(lp LogicalPlan) { // BuildKeyInfo implements LogicalPlan BuildKeyInfo interface. func (la *LogicalAggregation) BuildKeyInfo(selfSchema *expression.Schema, childSchema []*expression.Schema) { - if la.IsPartialModeAgg() { + // According to the issue#46962, we can ignore the judgment of partial agg + // Sometimes, the agg inside of subquery and there is a true condition in where clause, the agg function is empty. + // For example, ``` select xxxx from xxx WHERE TRUE = ALL ( SELECT TRUE GROUP BY 1 LIMIT 1 ) IS NULL IS NOT NULL; + // In this case, the agg is complete mode and we can ignore this check. + if len(la.AggFuncs) != 0 && la.IsPartialModeAgg() { return } la.logicalSchemaProducer.BuildKeyInfo(selfSchema, childSchema) diff --git a/planner/core/testdata/plan_suite_in.json b/planner/core/testdata/plan_suite_in.json index 71460213ec156..1def63b323f13 100644 --- a/planner/core/testdata/plan_suite_in.json +++ b/planner/core/testdata/plan_suite_in.json @@ -1157,5 +1157,13 @@ "select * from employee where dept_id = 1 union all ( select * from employee where dept_id = 1 order by employee_id) union all ( select * from employee where dept_id = 1 union all ( select * from employee where dept_id = 1 order by employee_id ) limit 1);", "select * from employee where dept_id = 1 union all ( select * from employee where dept_id = 1 order by employee_id) union all ( select * from employee where dept_id = 1 union all ( select * from employee where dept_id = 1 order by employee_id ) order by 1 limit 1);" ] + }, + { + "name": "TestAlwaysTruePredicateWithSubquery", + "cases" : [ + "SHOW ERRORS WHERE TRUE = ALL ( SELECT TRUE GROUP BY 1 LIMIT 1 ) IS NULL IS NOT NULL;", + "explain select * from t WHERE TRUE = ALL ( SELECT TRUE GROUP BY 1 LIMIT 1 ) IS NULL IS NOT NULL;", + "explain select * from t WHERE TRUE = ALL ( SELECT TRUE from t GROUP BY 1 LIMIT 1 ) is null is not null;" + ] } ] diff --git a/planner/core/testdata/plan_suite_out.json b/planner/core/testdata/plan_suite_out.json index dbce78a61198b..12d14d668c032 100644 --- a/planner/core/testdata/plan_suite_out.json +++ b/planner/core/testdata/plan_suite_out.json @@ -7043,5 +7043,43 @@ "Warning": null } ] + }, + { + "Name": "TestAlwaysTruePredicateWithSubquery", + "Cases": [ + { + "SQL": "SHOW ERRORS WHERE TRUE = ALL ( SELECT TRUE GROUP BY 1 LIMIT 1 ) IS NULL IS NOT NULL;", + "Plan": null, + "Warning": null + }, + { + "SQL": "explain select * from t WHERE TRUE = ALL ( SELECT TRUE GROUP BY 1 LIMIT 1 ) IS NULL IS NOT NULL;", + "Plan": [ + "HashJoin_14 10000.00 root CARTESIAN inner join", + "├─StreamAgg_19(Build) 1.00 root funcs:count(1)->Column#13", + "│ └─Limit_22 1.00 root offset:0, count:1", + "│ └─HashAgg_23 1.00 root group by:1, ", + "│ └─TableDual_24 1.00 root rows:1", + "└─TableReader_17(Probe) 10000.00 root data:TableFullScan_16", + " └─TableFullScan_16 10000.00 cop[tikv] table:t keep order:false, stats:pseudo" + ], + "Warning": null + }, + { + "SQL": "explain select * from t WHERE TRUE = ALL ( SELECT TRUE from t GROUP BY 1 LIMIT 1 ) is null is not null;", + "Plan": [ + "HashJoin_14 10000.00 root CARTESIAN inner join", + "├─StreamAgg_19(Build) 1.00 root funcs:count(1)->Column#16", + "│ └─Limit_22 1.00 root offset:0, count:1", + "│ └─HashAgg_27 1.00 root group by:Column#17, funcs:firstrow(Column#18)->test.t.a, funcs:firstrow(Column#19)->test.t.b, funcs:firstrow(Column#20)->test.t._tidb_rowid", + "│ └─TableReader_28 1.00 root data:HashAgg_23", + "│ └─HashAgg_23 1.00 cop[tikv] group by:1, funcs:firstrow(test.t.a)->Column#18, funcs:firstrow(test.t.b)->Column#19, funcs:firstrow(test.t._tidb_rowid)->Column#20", + "│ └─TableFullScan_26 10000.00 cop[tikv] table:t keep order:false, stats:pseudo", + "└─TableReader_17(Probe) 10000.00 root data:TableFullScan_16", + " └─TableFullScan_16 10000.00 cop[tikv] table:t keep order:false, stats:pseudo" + ], + "Warning": null + } + ] } ]