From ac819bcf551706b33e585876245c7571a963b042 Mon Sep 17 00:00:00 2001 From: Kenan Yao Date: Sun, 9 Sep 2018 18:30:21 +0800 Subject: [PATCH 1/4] plan: return table dual when filter is false/null Impose this check after constant propagation --- plan/rule_predicate_push_down.go | 34 +++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/plan/rule_predicate_push_down.go b/plan/rule_predicate_push_down.go index 16f14b8f5c363..7adc89b7f9c86 100644 --- a/plan/rule_predicate_push_down.go +++ b/plan/rule_predicate_push_down.go @@ -34,6 +34,12 @@ func addSelection(p LogicalPlan, child LogicalPlan, conditions []expression.Expr return } conditions = expression.PropagateConstant(p.context(), conditions) + // Return table dual when filter is constant false or null + dual := conds2TableDual(child, conditions) + if dual != nil { + p.Children()[chIdx] = dual + return + } selection := LogicalSelection{Conditions: conditions}.init(p.context()) selection.SetChildren(child) p.Children()[chIdx] = selection @@ -55,6 +61,11 @@ func (p *LogicalSelection) PredicatePushDown(predicates []expression.Expression) retConditions, child := p.children[0].PredicatePushDown(append(p.Conditions, predicates...)) if len(retConditions) > 0 { p.Conditions = expression.PropagateConstant(p.ctx, retConditions) + // Return table dual when filter is constant false or null + dual := conds2TableDual(p, p.Conditions) + if dual != nil { + return nil, dual + } return nil, p } return nil, child @@ -129,7 +140,13 @@ func (p *LogicalJoin) PredicatePushDown(predicates []expression.Expression) (ret tempCond = append(tempCond, p.OtherConditions...) tempCond = append(tempCond, predicates...) tempCond = expression.ExtractFiltersFromDNFs(p.ctx, tempCond) - equalCond, leftPushCond, rightPushCond, otherCond = extractOnCondition(expression.PropagateConstant(p.ctx, tempCond), leftPlan, rightPlan, true, true) + tempCond = expression.PropagateConstant(p.ctx, tempCond) + // Return table dual when filter is constant false or null + dual := conds2TableDual(p, tempCond) + if dual != nil { + return ret, dual + } + equalCond, leftPushCond, rightPushCond, otherCond = extractOnCondition(tempCond, leftPlan, rightPlan, true, true) p.LeftConditions = nil p.RightConditions = nil p.EqualConditions = equalCond @@ -375,3 +392,18 @@ func deriveOtherConditions(p *LogicalJoin, deriveLeft bool, deriveRight bool) (l } return } + +// conds2TableDual build a LogicalTableDual if cond is constant false or null +func conds2TableDual(p LogicalPlan, conds []expression.Expression) LogicalPlan { + if len(conds) == 1 { + if con, ok := conds[0].(*expression.Constant); ok { + sc := p.context().GetSessionVars().StmtCtx + if isTrue, err := con.Value.ToBool(sc); (err == nil && isTrue == 0) || con.Value.IsNull() { + dual := LogicalTableDual{}.init(p.context()) + dual.SetSchema(p.Schema()) + return dual + } + } + } + return nil +} From 8a65cbdac8893af7e112448410115644751604dc Mon Sep 17 00:00:00 2001 From: Kenan Yao Date: Sun, 9 Sep 2018 18:39:21 +0800 Subject: [PATCH 2/4] refactor conds2TableDual --- plan/rule_predicate_push_down.go | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/plan/rule_predicate_push_down.go b/plan/rule_predicate_push_down.go index 7adc89b7f9c86..6fb2a756080a6 100644 --- a/plan/rule_predicate_push_down.go +++ b/plan/rule_predicate_push_down.go @@ -395,15 +395,18 @@ func deriveOtherConditions(p *LogicalJoin, deriveLeft bool, deriveRight bool) (l // conds2TableDual build a LogicalTableDual if cond is constant false or null func conds2TableDual(p LogicalPlan, conds []expression.Expression) LogicalPlan { - if len(conds) == 1 { - if con, ok := conds[0].(*expression.Constant); ok { - sc := p.context().GetSessionVars().StmtCtx - if isTrue, err := con.Value.ToBool(sc); (err == nil && isTrue == 0) || con.Value.IsNull() { - dual := LogicalTableDual{}.init(p.context()) - dual.SetSchema(p.Schema()) - return dual - } - } + if len(conds) != 1 { + return nil + } + con, ok := conds[0].(*expression.Constant) + if !ok { + return nil + } + sc := p.context().GetSessionVars().StmtCtx + if isTrue, err := con.Value.ToBool(sc); (err == nil && isTrue == 0) || con.Value.IsNull() { + dual := LogicalTableDual{}.init(p.context()) + dual.SetSchema(p.Schema()) + return dual } return nil } From ab70184914730fd54ba3b18716cee170885aec25 Mon Sep 17 00:00:00 2001 From: Kenan Yao Date: Sun, 9 Sep 2018 21:01:58 +0800 Subject: [PATCH 3/4] add unit test --- plan/logical_plan_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plan/logical_plan_test.go b/plan/logical_plan_test.go index ef272c11545e4..b3f5fabeccfa6 100644 --- a/plan/logical_plan_test.go +++ b/plan/logical_plan_test.go @@ -427,6 +427,11 @@ func (s *testPlanSuite) TestPredicatePushDown(c *C) { sql: "select t1.a, t2.a from t as t1 left join t as t2 on t1.a = t2.a where t1.a < 1.0", best: "Join{DataScan(t1)->DataScan(t2)}(t1.a,t2.a)->Projection", }, + // issue #7728 + { + sql: "select * from t t1 join t t2 on t1.a = t2.a where t2.a = null", + best: "Dual->Projection", + }, } for _, ca := range tests { comment := Commentf("for %s", ca.sql) From acf1818d579d937eec9d8e3b06220c4208738cf6 Mon Sep 17 00:00:00 2001 From: Kenan Yao Date: Mon, 10 Sep 2018 01:45:26 +0800 Subject: [PATCH 4/4] address comments to fix comment format --- plan/rule_predicate_push_down.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plan/rule_predicate_push_down.go b/plan/rule_predicate_push_down.go index 26e5a0e17bb03..75753f8133644 100644 --- a/plan/rule_predicate_push_down.go +++ b/plan/rule_predicate_push_down.go @@ -34,7 +34,7 @@ func addSelection(p LogicalPlan, child LogicalPlan, conditions []expression.Expr return } conditions = expression.PropagateConstant(p.context(), conditions) - // Return table dual when filter is constant false or null + // Return table dual when filter is constant false or null. dual := conds2TableDual(child, conditions) if dual != nil { p.Children()[chIdx] = dual @@ -61,7 +61,7 @@ func (p *LogicalSelection) PredicatePushDown(predicates []expression.Expression) retConditions, child := p.children[0].PredicatePushDown(append(p.Conditions, predicates...)) if len(retConditions) > 0 { p.Conditions = expression.PropagateConstant(p.ctx, retConditions) - // Return table dual when filter is constant false or null + // Return table dual when filter is constant false or null. dual := conds2TableDual(p, p.Conditions) if dual != nil { return nil, dual @@ -141,7 +141,7 @@ func (p *LogicalJoin) PredicatePushDown(predicates []expression.Expression) (ret tempCond = append(tempCond, predicates...) tempCond = expression.ExtractFiltersFromDNFs(p.ctx, tempCond) tempCond = expression.PropagateConstant(p.ctx, tempCond) - // Return table dual when filter is constant false or null + // Return table dual when filter is constant false or null. dual := conds2TableDual(p, tempCond) if dual != nil { return ret, dual @@ -396,7 +396,7 @@ func deriveOtherConditions(p *LogicalJoin, deriveLeft bool, deriveRight bool) (l return } -// conds2TableDual build a LogicalTableDual if cond is constant false or null +// conds2TableDual builds a LogicalTableDual if cond is constant false or null. func conds2TableDual(p LogicalPlan, conds []expression.Expression) LogicalPlan { if len(conds) != 1 { return nil