Skip to content

Commit

Permalink
planner: fix column pruning bug for Apply and Join (#24369) (#24437)
Browse files Browse the repository at this point in the history
  • Loading branch information
ti-srebot authored May 26, 2021
1 parent 11977a2 commit 25b4276
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 0 deletions.
29 changes: 29 additions & 0 deletions planner/core/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2870,6 +2870,35 @@ func (s *testIntegrationSuite) TestReorderSimplifiedOuterJoins(c *C) {
}
}

// Apply operator may got panic because empty Projection is eliminated.
func (s *testIntegrationSerialSuite) TestIssue23887(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t;")
tk.MustExec("create table t(a int, b int);")
tk.MustExec("insert into t values(1, 2), (3, 4);")
var input []string
var output []struct {
SQL string
Plan []string
Res []string
}
s.testData.GetTestCases(c, &input, &output)
for i, tt := range input {
s.testData.OnRecord(func() {
output[i].SQL = tt
output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery("explain format = 'brief' " + tt).Rows())
output[i].Res = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Sort().Rows())
})
tk.MustQuery("explain format = 'brief' " + tt).Check(testkit.Rows(output[i].Plan...))
tk.MustQuery(tt).Sort().Check(testkit.Rows(output[i].Res...))
}

tk.MustExec("drop table if exists t1;")
tk.MustExec("create table t1 (c1 int primary key, c2 int, c3 int, index c2 (c2));")
tk.MustQuery("select count(1) from (select count(1) from (select * from t1 where c3 = 100) k) k2;").Check(testkit.Rows("1"))
}

func (s *testIntegrationSerialSuite) TestDeleteStmt(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test")
Expand Down
26 changes: 26 additions & 0 deletions planner/core/rule_column_pruning.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,11 +314,13 @@ func (p *LogicalJoin) PruneColumns(parentUsedCols []*expression.Column) error {
if err != nil {
return err
}
addConstOneForEmptyProjection(p.children[0])

err = p.children[1].PruneColumns(rightCols)
if err != nil {
return err
}
addConstOneForEmptyProjection(p.children[1])

p.mergeSchema()
if p.JoinType == LeftOuterSemiJoin || p.JoinType == AntiLeftOuterSemiJoin {
Expand All @@ -337,6 +339,7 @@ func (la *LogicalApply) PruneColumns(parentUsedCols []*expression.Column) error
if err != nil {
return err
}
addConstOneForEmptyProjection(la.children[1])

la.CorCols = extractCorColumnsBySchema4LogicalPlan(la.children[1], la.children[0].Schema())
for _, col := range la.CorCols {
Expand All @@ -347,6 +350,7 @@ func (la *LogicalApply) PruneColumns(parentUsedCols []*expression.Column) error
if err != nil {
return err
}
addConstOneForEmptyProjection(la.children[0])

la.mergeSchema()
return nil
Expand Down Expand Up @@ -431,3 +435,25 @@ func (p *LogicalLimit) PruneColumns(parentUsedCols []*expression.Column) error {
func (*columnPruner) name() string {
return "column_prune"
}

// By add const one, we can avoid empty Projection is eliminated.
// Because in some cases, Projectoin cannot be eliminated even its output is empty.
func addConstOneForEmptyProjection(p LogicalPlan) {
proj, ok := p.(*LogicalProjection)
if !ok {
return
}
if proj.Schema().Len() != 0 {
return
}

constOne := expression.NewOne()
proj.schema.Append(&expression.Column{
UniqueID: proj.ctx.GetSessionVars().AllocPlanColumnID(),
RetType: constOne.GetType(),
})
proj.Exprs = append(proj.Exprs, &expression.Constant{
Value: constOne.Value,
RetType: constOne.GetType(),
})
}
6 changes: 6 additions & 0 deletions planner/core/testdata/integration_serial_suite_in.json
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,12 @@
"desc format = 'brief' select * from (select id from t group by id) C join (select sum(b),id from (select t.id, t1.id as b from t join (select id, count(*) as c from t group by id) t1 on t.id=t1.id)A group by id)B on C.id=b.id"
]
},
{
"name": "TestIssue23887",
"cases": [
"select (2) in (select b from t) from (select t.a < (select t.a from t t1 limit 1) from t) t"
]
},
{
"name": "TestMergeContinuousSelections",
"cases": [
Expand Down
26 changes: 26 additions & 0 deletions planner/core/testdata/integration_serial_suite_out.json
Original file line number Diff line number Diff line change
Expand Up @@ -2283,6 +2283,32 @@
}
]
},
{
"Name": "TestIssue23887",
"Cases": [
{
"SQL": "select (2) in (select b from t) from (select t.a < (select t.a from t t1 limit 1) from t) t",
"Plan": [
"HashJoin 10000.00 root CARTESIAN left outer semi join, other cond:eq(2, test.t.b)",
"├─TableReader(Build) 10000.00 root data:TableFullScan",
"│ └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo",
"└─Projection(Probe) 10000.00 root 1->Column#27",
" └─Apply 10000.00 root CARTESIAN left outer join",
" ├─TableReader(Build) 10000.00 root data:TableFullScan",
" │ └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo",
" └─Projection(Probe) 1.00 root 1->Column#25",
" └─Limit 1.00 root offset:0, count:1",
" └─TableReader 1.00 root data:Limit",
" └─Limit 1.00 cop[tikv] offset:0, count:1",
" └─TableFullScan 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
],
"Res": [
"1",
"1"
]
}
]
},
{
"Name": "TestMergeContinuousSelections",
"Cases": [
Expand Down

0 comments on commit 25b4276

Please sign in to comment.