diff --git a/expression/integration_test.go b/expression/integration_test.go index 021745a0dfbea..b5f3db5beb870 100755 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -8251,3 +8251,13 @@ func (s *testIntegrationSuite) TestJiraSetInnoDBDefaultRowFormat(c *C) { tk.MustQuery("SHOW VARIABLES LIKE 'innodb_file_format'").Check(testkit.Rows("innodb_file_format Barracuda")) tk.MustQuery("SHOW VARIABLES LIKE 'innodb_large_prefix'").Check(testkit.Rows("innodb_large_prefix ON")) } + +func (s *testIntegrationSuite) TestIssue27233(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test;") + tk.MustExec("drop table if exists t;") + tk.MustExec("CREATE TABLE `t` (\n `COL1` tinyint(45) NOT NULL,\n `COL2` tinyint(45) NOT NULL,\n PRIMARY KEY (`COL1`,`COL2`) /*T![clustered_index] NONCLUSTERED */\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;") + tk.MustExec("insert into t values(122,100),(124,-22),(124,34),(127,103);") + tk.MustQuery("SELECT col2 FROM t AS T1 WHERE ( SELECT count(DISTINCT COL1, COL2) FROM t AS T2 WHERE T2.COL1 > T1.COL1 ) > 2 ;"). + Check(testkit.Rows("100")) +} diff --git a/planner/core/physical_plan_test.go b/planner/core/physical_plan_test.go index 91a1cff9a420f..f51b7f34acbd1 100644 --- a/planner/core/physical_plan_test.go +++ b/planner/core/physical_plan_test.go @@ -1548,3 +1548,136 @@ func (s *testPlanSuite) TestHintFromDiffDatabase(c *C) { c.Assert(core.ToString(p), Equals, output[i].Plan, comment) } } +<<<<<<< HEAD +======= + +func (s *testPlanSuite) TestNthPlanHintWithExplain(c *C) { + defer testleak.AfterTest(c)() + store, dom, err := newStoreWithBootstrap() + c.Assert(err, IsNil) + tk := testkit.NewTestKit(c, store) + defer func() { + dom.Close() + store.Close() + }() + se, err := session.CreateSession4Test(store) + c.Assert(err, IsNil) + ctx := context.Background() + _, err = se.Execute(ctx, "use test") + c.Assert(err, IsNil) + _, err = se.Execute(ctx, `drop table if exists test.tt`) + c.Assert(err, IsNil) + _, err = se.Execute(ctx, `create table test.tt (a int,b int, index(a), index(b));`) + c.Assert(err, IsNil) + + _, err = se.Execute(ctx, "insert into tt values (1, 1), (2, 2), (3, 4)") + c.Assert(err, IsNil) + + tk.MustExec(`set @@tidb_partition_prune_mode='` + string(variable.Static) + `'`) + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, ts := range input { + s.testData.OnRecord(func() { + output[i].SQL = ts + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery("explain format = 'brief' " + ts).Rows()) + }) + tk.MustQuery("explain format = 'brief' " + ts).Check(testkit.Rows(output[i].Plan...)) + } + + // This assert makes sure a query with or without nth_plan() hint output exactly the same plan(including plan ID). + // The query below is the same as queries in the testdata except for nth_plan() hint. + // Currently its output is the same as the second test case in the testdata, which is `output[1]`. If this doesn't + // hold in the future, you may need to modify this. + tk.MustQuery("explain format = 'brief' select * from test.tt where a=1 and b=1").Check(testkit.Rows(output[1].Plan...)) +} + +func (s *testPlanSuite) TestEnumIndex(c *C) { + var ( + input []string + output []struct { + SQL string + Plan []string + Result []string + } + ) + s.testData.GetTestCases(c, &input, &output) + store, dom, err := newStoreWithBootstrap() + c.Assert(err, IsNil) + defer func() { + dom.Close() + store.Close() + }() + tk := testkit.NewTestKit(c, store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t(e enum('c','b','a',''), index idx(e))") + tk.MustExec("insert ignore into t values(0),(1),(2),(3),(4);") + + for i, ts := range input { + s.testData.OnRecord(func() { + output[i].SQL = ts + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery("explain format='brief'" + ts).Rows()) + output[i].Result = s.testData.ConvertRowsToStrings(tk.MustQuery(ts).Sort().Rows()) + }) + tk.MustQuery("explain format='brief' " + ts).Check(testkit.Rows(output[i].Plan...)) + tk.MustQuery(ts).Sort().Check(testkit.Rows(output[i].Result...)) + } +} + +func (s *testPlanSuite) TestIssue27233(c *C) { + var ( + input []string + output []struct { + SQL string + Plan []string + Result []string + } + ) + s.testData.GetTestCases(c, &input, &output) + store, dom, err := newStoreWithBootstrap() + c.Assert(err, IsNil) + defer func() { + dom.Close() + store.Close() + }() + tk := testkit.NewTestKit(c, store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("CREATE TABLE `PK_S_MULTI_31` (\n `COL1` tinyint(45) NOT NULL,\n `COL2` tinyint(45) NOT NULL,\n PRIMARY KEY (`COL1`,`COL2`) /*T![clustered_index] NONCLUSTERED */\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;") + tk.MustExec("insert into PK_S_MULTI_31 values(122,100),(124,-22),(124,34),(127,103);") + + for i, ts := range input { + s.testData.OnRecord(func() { + output[i].SQL = ts + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery("explain format='brief'" + ts).Rows()) + output[i].Result = s.testData.ConvertRowsToStrings(tk.MustQuery(ts).Sort().Rows()) + }) + tk.MustQuery("explain format='brief' " + ts).Check(testkit.Rows(output[i].Plan...)) + tk.MustQuery(ts).Sort().Check(testkit.Rows(output[i].Result...)) + } +} + +func (s *testPlanSuite) TestPossibleProperties(c *C) { + store, dom, err := newStoreWithBootstrap() + c.Assert(err, IsNil) + defer func() { + dom.Close() + store.Close() + }() + tk := testkit.NewTestKit(c, store) + tk.MustExec("use test") + tk.MustExec("drop table if exists student, sc") + tk.MustExec("create table student(id int primary key auto_increment, name varchar(4) not null)") + tk.MustExec("create table sc(id int primary key auto_increment, student_id int not null, course_id int not null, score int not null)") + tk.MustExec("insert into student values (1,'s1'), (2,'s2')") + tk.MustExec("insert into sc (student_id, course_id, score) values (1,1,59), (1,2,57), (1,3,76), (2,1,99), (2,2,100), (2,3,100)") + tk.MustQuery("select /*+ stream_agg() */ a.id, avg(b.score) as afs from student a join sc b on a.id = b.student_id where b.score < 60 group by a.id having count(b.course_id) >= 2").Check(testkit.Rows( + "1 58.0000", + )) +} +>>>>>>> 1c6c54833... planner: add missing column for Apply convert to Join (#27246) diff --git a/planner/core/rule_decorrelate.go b/planner/core/rule_decorrelate.go index 62e8a55f57612..b73935564f211 100644 --- a/planner/core/rule_decorrelate.go +++ b/planner/core/rule_decorrelate.go @@ -179,22 +179,37 @@ func (s *decorrelateSolver) optimize(ctx context.Context, p LogicalPlan) (Logica resetNotNullFlag(apply.schema, outerPlan.Schema().Len(), apply.schema.Len()) for i, aggFunc := range agg.AggFuncs { +<<<<<<< HEAD switch expr := aggFunc.Args[0].(type) { case *expression.Column: if idx := apply.schema.ColumnIndex(expr); idx != -1 { desc, err := aggregation.NewAggFuncDesc(agg.ctx, agg.AggFuncs[i].Name, []expression.Expression{apply.schema.Columns[idx]}, false) if err != nil { return nil, err +======= + aggArgs := make([]expression.Expression, 0, len(aggFunc.Args)) + for _, arg := range aggFunc.Args { + switch expr := arg.(type) { + case *expression.Column: + if idx := apply.schema.ColumnIndex(expr); idx != -1 { + aggArgs = append(aggArgs, apply.schema.Columns[idx]) + } else { + aggArgs = append(aggArgs, expr) +>>>>>>> 1c6c54833... planner: add missing column for Apply convert to Join (#27246) } - newAggFuncs = append(newAggFuncs, desc) + case *expression.ScalarFunction: + expr.RetType = expr.RetType.Clone() + expr.RetType.Flag &= ^mysql.NotNullFlag + aggArgs = append(aggArgs, expr) + default: + aggArgs = append(aggArgs, expr) } - case *expression.ScalarFunction: - expr.RetType = expr.RetType.Clone() - expr.RetType.Flag &= ^mysql.NotNullFlag - newAggFuncs = append(newAggFuncs, aggFunc) - default: - newAggFuncs = append(newAggFuncs, aggFunc) } + desc, err := aggregation.NewAggFuncDesc(agg.ctx, agg.AggFuncs[i].Name, aggArgs, agg.AggFuncs[i].HasDistinct) + if err != nil { + return nil, err + } + newAggFuncs = append(newAggFuncs, desc) } agg.AggFuncs = newAggFuncs np, err := s.optimize(ctx, p) diff --git a/planner/core/testdata/plan_suite_in.json b/planner/core/testdata/plan_suite_in.json index 63caf01065252..e1266772eeee8 100644 --- a/planner/core/testdata/plan_suite_in.json +++ b/planner/core/testdata/plan_suite_in.json @@ -639,5 +639,59 @@ "cases": [ "select /*+ inl_hash_join(test.t1) */ * from test.t2 join test.t1 on test.t2.a = test.t1.a" ] +<<<<<<< HEAD +======= + }, + { + "name": "TestNthPlanHintWithExplain", + "cases": [ + "select /*+nth_plan(1)*/ * from test.tt where a=1 and b=1", + "select /*+nth_plan(2)*/ * from test.tt where a=1 and b=1;", + "select /*+nth_plan(3)*/ * from test.tt where a=1 and b=1;", + "select /*+nth_plan(2)*/ * from test.tt where a=1 and b=1;", + "select * from test.tt where a=1 and b=1" + ] + }, + { + "name": "TestEliminateMaxOneRow", + "cases": [ + "select a from t2 where t2.a < (select t1.a from t1 where t1.a = t2.a);", + "select a from t2 where t2.a < (select t1.a from t1 where t1.b = t2.b and t1.a is null);", + "select a from t2 where t2.a < (select t3.a from t3 where t3.a = t2.a);" + ] + }, + { + "name": "TestEnumIndex", + "cases": [ + "select e from t where e = 'b'", + "select e from t where e != 'b'", + "select e from t where e > 'b'", + "select e from t where e >= 'b'", + "select e from t where e < 'b'", + "select e from t where e <= 'b'", + "select e from t where e = 2", + "select e from t where e != 2", + "select e from t where e > 2", + "select e from t where e >= 2", + "select e from t where e < 2", + "select e from t where e <= 2", + + // Out of range + "select e from t where e > ''", + "select e from t where e > 'd'", + "select e from t where e > -1", + "select e from t where e > 5", + + // zero-value + "select e from t where e = ''", + "select e from t where e != ''" + ] + }, + { + "name": "TestIssue27233", + "cases": [ + "SELECT col2 FROM PK_S_MULTI_31 AS T1 WHERE (SELECT count(DISTINCT COL1, COL2) FROM PK_S_MULTI_31 AS T2 WHERE T2.COL1>T1.COL1)>2 order by col2;" + ] +>>>>>>> 1c6c54833... planner: add missing column for Apply convert to Join (#27246) } ] diff --git a/planner/core/testdata/plan_suite_out.json b/planner/core/testdata/plan_suite_out.json index 61ce5740fcf67..dce90dcb4edb1 100644 --- a/planner/core/testdata/plan_suite_out.json +++ b/planner/core/testdata/plan_suite_out.json @@ -2119,5 +2119,336 @@ "Plan": "IndexHashJoin{IndexReader(Index(t2.idx_a)[[-inf,+inf]])->IndexReader(Index(t1.idx_a)[[NULL,+inf]]->Sel([not(isnull(test.t1.a))]))}(test.t2.a,test.t1.a)" } ] +<<<<<<< HEAD +======= + }, + { + "Name": "TestNthPlanHintWithExplain", + "Cases": [ + { + "SQL": "select /*+nth_plan(1)*/ * from test.tt where a=1 and b=1", + "Plan": [ + "TableReader 0.01 root data:Selection", + "└─Selection 0.01 cop[tikv] eq(test.tt.a, 1), eq(test.tt.b, 1)", + " └─TableFullScan 10000.00 cop[tikv] table:tt keep order:false, stats:pseudo" + ] + }, + { + "SQL": "select /*+nth_plan(2)*/ * from test.tt where a=1 and b=1;", + "Plan": [ + "IndexLookUp 0.01 root ", + "├─IndexRangeScan(Build) 10.00 cop[tikv] table:tt, index:a(a) range:[1,1], keep order:false, stats:pseudo", + "└─Selection(Probe) 0.01 cop[tikv] eq(test.tt.b, 1)", + " └─TableRowIDScan 10.00 cop[tikv] table:tt keep order:false, stats:pseudo" + ] + }, + { + "SQL": "select /*+nth_plan(3)*/ * from test.tt where a=1 and b=1;", + "Plan": [ + "IndexLookUp 0.01 root ", + "├─IndexRangeScan(Build) 10.00 cop[tikv] table:tt, index:b(b) range:[1,1], keep order:false, stats:pseudo", + "└─Selection(Probe) 0.01 cop[tikv] eq(test.tt.a, 1)", + " └─TableRowIDScan 10.00 cop[tikv] table:tt keep order:false, stats:pseudo" + ] + }, + { + "SQL": "select /*+nth_plan(2)*/ * from test.tt where a=1 and b=1;", + "Plan": [ + "IndexLookUp 0.01 root ", + "├─IndexRangeScan(Build) 10.00 cop[tikv] table:tt, index:a(a) range:[1,1], keep order:false, stats:pseudo", + "└─Selection(Probe) 0.01 cop[tikv] eq(test.tt.b, 1)", + " └─TableRowIDScan 10.00 cop[tikv] table:tt keep order:false, stats:pseudo" + ] + }, + { + "SQL": "select * from test.tt where a=1 and b=1", + "Plan": [ + "IndexLookUp 0.01 root ", + "├─IndexRangeScan(Build) 10.00 cop[tikv] table:tt, index:a(a) range:[1,1], keep order:false, stats:pseudo", + "└─Selection(Probe) 0.01 cop[tikv] eq(test.tt.b, 1)", + " └─TableRowIDScan 10.00 cop[tikv] table:tt keep order:false, stats:pseudo" + ] + } + ] + }, + { + "Name": "TestEliminateMaxOneRow", + "Cases": [ + { + "SQL": "select a from t2 where t2.a < (select t1.a from t1 where t1.a = t2.a);", + "Plan": [ + "HashJoin 9990.00 root inner join, equal:[eq(test.t2.a, test.t1.a)], other cond:lt(test.t2.a, test.t1.a)", + "├─IndexReader(Build) 7992.00 root index:Selection", + "│ └─Selection 7992.00 cop[tikv] lt(test.t1.a, test.t1.a)", + "│ └─IndexFullScan 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:false, stats:pseudo", + "└─TableReader(Probe) 7992.00 root data:Selection", + " └─Selection 7992.00 cop[tikv] lt(test.t2.a, test.t2.a), not(isnull(test.t2.a))", + " └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo" + ], + "Result": null + }, + { + "SQL": "select a from t2 where t2.a < (select t1.a from t1 where t1.b = t2.b and t1.a is null);", + "Plan": [ + "Projection 9990.00 root test.t2.a", + "└─Apply 9990.00 root CARTESIAN inner join, other cond:lt(test.t2.a, test.t1.a)", + " ├─TableReader(Build) 9990.00 root data:Selection", + " │ └─Selection 9990.00 cop[tikv] not(isnull(test.t2.a))", + " │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + " └─Selection(Probe) 0.80 root not(isnull(test.t1.a))", + " └─MaxOneRow 1.00 root ", + " └─IndexLookUp 0.00 root ", + " ├─IndexRangeScan(Build) 1.00 cop[tikv] table:t1, index:idx_a(a) range:[NULL,NULL], keep order:false, stats:pseudo", + " └─Selection(Probe) 0.00 cop[tikv] eq(test.t1.b, test.t2.b)", + " └─TableRowIDScan 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo" + ], + "Result": null + }, + { + "SQL": "select a from t2 where t2.a < (select t3.a from t3 where t3.a = t2.a);", + "Plan": [ + "Projection 9990.00 root test.t2.a", + "└─Apply 9990.00 root CARTESIAN inner join, other cond:lt(test.t2.a, test.t3.a)", + " ├─TableReader(Build) 9990.00 root data:Selection", + " │ └─Selection 9990.00 cop[tikv] not(isnull(test.t2.a))", + " │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + " └─Selection(Probe) 0.80 root not(isnull(test.t3.a))", + " └─MaxOneRow 1.00 root ", + " └─IndexReader 2.00 root index:IndexRangeScan", + " └─IndexRangeScan 2.00 cop[tikv] table:t3, index:idx_abc(a, b, c) range: decided by [eq(test.t3.a, test.t2.a)], keep order:false, stats:pseudo" + ], + "Result": null + } + ] + }, + { + "Name": "TestEnumIndex", + "Cases": [ + { + "SQL": "select e from t where e = 'b'", + "Plan": [ + "IndexReader 10.00 root index:IndexRangeScan", + "└─IndexRangeScan 10.00 cop[tikv] table:t, index:idx(e) range:[\"b\",\"b\"], keep order:false, stats:pseudo" + ], + "Result": [ + "b" + ] + }, + { + "SQL": "select e from t where e != 'b'", + "Plan": [ + "IndexReader 40.00 root index:IndexRangeScan", + "└─IndexRangeScan 40.00 cop[tikv] table:t, index:idx(e) range:[\"\",\"\"], [\"c\",\"c\"], [\"a\",\"a\"], [\"\",\"\"], keep order:false, stats:pseudo" + ], + "Result": [ + "", + "", + "a", + "c" + ] + }, + { + "SQL": "select e from t where e > 'b'", + "Plan": [ + "IndexReader 10.00 root index:IndexRangeScan", + "└─IndexRangeScan 10.00 cop[tikv] table:t, index:idx(e) range:[\"c\",\"c\"], keep order:false, stats:pseudo" + ], + "Result": [ + "c" + ] + }, + { + "SQL": "select e from t where e >= 'b'", + "Plan": [ + "IndexReader 20.00 root index:IndexRangeScan", + "└─IndexRangeScan 20.00 cop[tikv] table:t, index:idx(e) range:[\"c\",\"c\"], [\"b\",\"b\"], keep order:false, stats:pseudo" + ], + "Result": [ + "b", + "c" + ] + }, + { + "SQL": "select e from t where e < 'b'", + "Plan": [ + "IndexReader 30.00 root index:IndexRangeScan", + "└─IndexRangeScan 30.00 cop[tikv] table:t, index:idx(e) range:[\"\",\"\"], [\"a\",\"a\"], [\"\",\"\"], keep order:false, stats:pseudo" + ], + "Result": [ + "", + "", + "a" + ] + }, + { + "SQL": "select e from t where e <= 'b'", + "Plan": [ + "IndexReader 40.00 root index:IndexRangeScan", + "└─IndexRangeScan 40.00 cop[tikv] table:t, index:idx(e) range:[\"\",\"\"], [\"b\",\"b\"], [\"a\",\"a\"], [\"\",\"\"], keep order:false, stats:pseudo" + ], + "Result": [ + "", + "", + "a", + "b" + ] + }, + { + "SQL": "select e from t where e = 2", + "Plan": [ + "IndexReader 10.00 root index:IndexRangeScan", + "└─IndexRangeScan 10.00 cop[tikv] table:t, index:idx(e) range:[\"b\",\"b\"], keep order:false, stats:pseudo" + ], + "Result": [ + "b" + ] + }, + { + "SQL": "select e from t where e != 2", + "Plan": [ + "IndexReader 6656.67 root index:IndexRangeScan", + "└─IndexRangeScan 6656.67 cop[tikv] table:t, index:idx(e) range:[-inf,\"b\"), (\"b\",+inf], keep order:false, stats:pseudo" + ], + "Result": [ + "", + "", + "a", + "c" + ] + }, + { + "SQL": "select e from t where e > 2", + "Plan": [ + "IndexReader 3333.33 root index:IndexRangeScan", + "└─IndexRangeScan 3333.33 cop[tikv] table:t, index:idx(e) range:(\"b\",+inf], keep order:false, stats:pseudo" + ], + "Result": [ + "", + "a" + ] + }, + { + "SQL": "select e from t where e >= 2", + "Plan": [ + "IndexReader 3333.33 root index:IndexRangeScan", + "└─IndexRangeScan 3333.33 cop[tikv] table:t, index:idx(e) range:[\"b\",+inf], keep order:false, stats:pseudo" + ], + "Result": [ + "", + "a", + "b" + ] + }, + { + "SQL": "select e from t where e < 2", + "Plan": [ + "IndexReader 3323.33 root index:IndexRangeScan", + "└─IndexRangeScan 3323.33 cop[tikv] table:t, index:idx(e) range:[-inf,\"b\"), keep order:false, stats:pseudo" + ], + "Result": [ + "", + "c" + ] + }, + { + "SQL": "select e from t where e <= 2", + "Plan": [ + "IndexReader 3323.33 root index:IndexRangeScan", + "└─IndexRangeScan 3323.33 cop[tikv] table:t, index:idx(e) range:[-inf,\"b\"], keep order:false, stats:pseudo" + ], + "Result": [ + "", + "b", + "c" + ] + }, + { + "SQL": "select e from t where e > ''", + "Plan": [ + "IndexReader 30.00 root index:IndexRangeScan", + "└─IndexRangeScan 30.00 cop[tikv] table:t, index:idx(e) range:[\"c\",\"c\"], [\"b\",\"b\"], [\"a\",\"a\"], keep order:false, stats:pseudo" + ], + "Result": [ + "a", + "b", + "c" + ] + }, + { + "SQL": "select e from t where e > 'd'", + "Plan": [ + "TableDual 0.00 root rows:0" + ], + "Result": null + }, + { + "SQL": "select e from t where e > -1", + "Plan": [ + "IndexReader 3333.33 root index:IndexRangeScan", + "└─IndexRangeScan 3333.33 cop[tikv] table:t, index:idx(e) range:[\"\",+inf], keep order:false, stats:pseudo" + ], + "Result": [ + "", + "", + "a", + "b", + "c" + ] + }, + { + "SQL": "select e from t where e > 5", + "Plan": [ + "IndexReader 3333.33 root index:IndexRangeScan", + "└─IndexRangeScan 3333.33 cop[tikv] table:t, index:idx(e) range:(\"\",+inf], keep order:false, stats:pseudo" + ], + "Result": null + }, + { + "SQL": "select e from t where e = ''", + "Plan": [ + "IndexReader 20.00 root index:IndexRangeScan", + "└─IndexRangeScan 20.00 cop[tikv] table:t, index:idx(e) range:[\"\",\"\"], [\"\",\"\"], keep order:false, stats:pseudo" + ], + "Result": [ + "", + "" + ] + }, + { + "SQL": "select e from t where e != ''", + "Plan": [ + "IndexReader 30.00 root index:IndexRangeScan", + "└─IndexRangeScan 30.00 cop[tikv] table:t, index:idx(e) range:[\"c\",\"c\"], [\"b\",\"b\"], [\"a\",\"a\"], keep order:false, stats:pseudo" + ], + "Result": [ + "a", + "b", + "c" + ] + } + ] + }, + { + "Name": "TestIssue27233", + "Cases": [ + { + "SQL": "SELECT col2 FROM PK_S_MULTI_31 AS T1 WHERE (SELECT count(DISTINCT COL1, COL2) FROM PK_S_MULTI_31 AS T2 WHERE T2.COL1>T1.COL1)>2 order by col2;", + "Plan": [ + "Sort 0.80 root test.pk_s_multi_31.col2", + "└─Projection 0.80 root test.pk_s_multi_31.col2", + " └─Selection 0.80 root gt(Column#7, 2)", + " └─HashAgg 1.00 root group by:test.pk_s_multi_31.col1, test.pk_s_multi_31.col2, funcs:firstrow(test.pk_s_multi_31.col2)->test.pk_s_multi_31.col2, funcs:count(distinct test.pk_s_multi_31.col1, test.pk_s_multi_31.col2)->Column#7", + " └─HashJoin 100000000.00 root CARTESIAN left outer join, other cond:gt(test.pk_s_multi_31.col1, test.pk_s_multi_31.col1)", + " ├─IndexReader(Build) 10000.00 root index:IndexFullScan", + " │ └─IndexFullScan 10000.00 cop[tikv] table:T2, index:PRIMARY(COL1, COL2) keep order:false, stats:pseudo", + " └─IndexReader(Probe) 10000.00 root index:IndexFullScan", + " └─IndexFullScan 10000.00 cop[tikv] table:T1, index:PRIMARY(COL1, COL2) keep order:false, stats:pseudo" + ], + "Result": [ + "100" + ] + } + ] +>>>>>>> 1c6c54833... planner: add missing column for Apply convert to Join (#27246) } ]