Skip to content

Commit

Permalink
plan, executor: refine projection elimination when projection is the…
Browse files Browse the repository at this point in the history
… inner child of an outer join (#5086) (#5148)
  • Loading branch information
XuHuaiyu authored and shenli committed Nov 19, 2017
1 parent 73b4c98 commit aef8142
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 3 deletions.
32 changes: 32 additions & 0 deletions executor/join_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,38 @@ func (s *testSuite) TestJoin(c *C) {
tk.MustExec("insert into t values(1,2), (5,3), (6,4)")
tk.MustExec("insert into t1 values(1), (2), (3)")
tk.MustQuery("select /*+ TIDB_INLJ(t1) */ t1.a from t1, t where t.a = 5 and t.b = t1.a").Check(testkit.Rows("3"))

// test issue#4997
tk.MustExec("drop table if exists t1, t2")
tk.MustExec(`
CREATE TABLE t1 (
pk int(11) NOT NULL AUTO_INCREMENT primary key,
a int(11) DEFAULT NULL,
b date DEFAULT NULL,
c varchar(1) DEFAULT NULL,
KEY a (a),
KEY b (b),
KEY c (c,a)
)`)
tk.MustExec(`
CREATE TABLE t2 (
pk int(11) NOT NULL AUTO_INCREMENT primary key,
a int(11) DEFAULT NULL,
b date DEFAULT NULL,
c varchar(1) DEFAULT NULL,
KEY a (a),
KEY b (b),
KEY c (c,a)
)`)
tk.MustExec(`insert into t1 value(1,1,"2000-11-11", null);`)
result = tk.MustQuery(`
SELECT table2.b AS field2 FROM
(
t1 AS table1 LEFT OUTER JOIN
(SELECT tmp_t2.* FROM ( t2 AS tmp_t1 RIGHT JOIN t1 AS tmp_t2 ON (tmp_t2.a = tmp_t1.a))) AS table2
ON (table2.c = table1.c)
) `)
result.Check(testkit.Rows("<nil>"))
}

func (s *testSuite) TestJoinCast(c *C) {
Expand Down
45 changes: 42 additions & 3 deletions plan/eliminate_projection.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/pingcap/tidb/context"
"github.com/pingcap/tidb/expression"
"github.com/pingcap/tidb/terror"
"github.com/pingcap/tidb/util/types"
)

// canProjectionBeEliminatedLoose checks whether a projection can be eliminated, returns true if
Expand Down Expand Up @@ -160,15 +161,53 @@ func (pe *projectionEliminater) eliminate(p LogicalPlan, replace map[string]*exp
if !(isProj && canEliminate && canProjectionBeEliminatedLoose(proj)) {
return p
}

child := p.Children()[0]
if join, ok := p.Parents()[0].(*LogicalJoin); ok {
pe.resetDefaultValues(join, p)
}
exprs := proj.Exprs
for i, col := range proj.Schema().Columns {
replace[string(col.HashCode())] = exprs[i].(*expression.Column)
}
err := RemovePlan(p)
terror.Log(errors.Trace(err))
return child.(LogicalPlan)
return p.Children()[0].(LogicalPlan)
}

// If the inner child of a Join is a Projection which been eliminated,
// and the schema of child plan of Projection is not consistent with
// the schema of Projection, the default values of Join should be reset.
func (pe *projectionEliminater) resetDefaultValues(join *LogicalJoin, prj Plan) {
prjChild := prj.Children()[0]
var joinInnerChild Plan
switch join.JoinType {
case LeftOuterJoin:
joinInnerChild = join.Children()[1]
case RightOuterJoin:
joinInnerChild = join.Children()[0]
default:
return
}
if joinInnerChild != prj {
return
}
var schemaIdxMap map[int]int
prjSchema := prj.Schema().Columns
childOfPrjSchema := prjChild.Schema().Columns
for i := 0; i < len(prjSchema); i++ {
for j := 0; j < len(childOfPrjSchema); j++ {
if prjSchema[i].Equal(childOfPrjSchema[j], nil) {
schemaIdxMap[i] = j
}
}
}
newDefaultValues := make([]types.Datum, len(childOfPrjSchema))
for i := range prjSchema {
if j, ok := schemaIdxMap[i]; ok {
newDefaultValues[j] = join.DefaultValues[i]
}
}
join.DefaultValues = newDefaultValues
return
}

func (p *LogicalJoin) replaceExprColumns(replace map[string]*expression.Column) {
Expand Down

0 comments on commit aef8142

Please sign in to comment.