diff --git a/executor/builder.go b/executor/builder.go index 4faa064034d73..cd11c5593b92a 100644 --- a/executor/builder.go +++ b/executor/builder.go @@ -111,7 +111,7 @@ func (b *executorBuilder) build(p plan.Plan) Executor { return b.buildSemiJoin(v) case *plan.PhysicalIndexJoin: return b.buildIndexLookUpJoin(v) - case *plan.Selection: + case *plan.PhysicalSelection: return b.buildSelection(v) case *plan.PhysicalAggregation: return b.buildAggregation(v) @@ -622,7 +622,7 @@ func (b *executorBuilder) buildAggregation(v *plan.PhysicalAggregation) Executor } } -func (b *executorBuilder) buildSelection(v *plan.Selection) Executor { +func (b *executorBuilder) buildSelection(v *plan.PhysicalSelection) Executor { exec := &SelectionExec{ baseExecutor: newBaseExecutor(v.Schema(), b.ctx, b.build(v.Children()[0])), Conditions: v.Conditions, diff --git a/plan/build_key_info.go b/plan/build_key_info.go index aba50c861bcae..39ad8914ef5c5 100644 --- a/plan/build_key_info.go +++ b/plan/build_key_info.go @@ -57,7 +57,7 @@ func (p *LogicalAggregation) buildKeyInfo() { // If a condition is the form of (uniqueKey = constant) or (uniqueKey = Correlated column), it returns at most one row. // This function will check it. -func (p *Selection) checkMaxOneRowCond(unique expression.Expression, constOrCorCol expression.Expression) bool { +func (p *LogicalSelection) checkMaxOneRowCond(unique expression.Expression, constOrCorCol expression.Expression) bool { col, ok := unique.(*expression.Column) if !ok { return false @@ -73,7 +73,7 @@ func (p *Selection) checkMaxOneRowCond(unique expression.Expression, constOrCorC return okCorCol } -func (p *Selection) buildKeyInfo() { +func (p *LogicalSelection) buildKeyInfo() { p.baseLogicalPlan.buildKeyInfo() p.schema.MaxOneRow = p.children[0].Schema().MaxOneRow for _, cond := range p.Conditions { diff --git a/plan/column_pruning.go b/plan/column_pruning.go index 216ef4628c36f..450e2435f05d2 100644 --- a/plan/column_pruning.go +++ b/plan/column_pruning.go @@ -77,7 +77,7 @@ func (p *Projection) PruneColumns(parentUsedCols []*expression.Column) { } // PruneColumns implements LogicalPlan interface. -func (p *Selection) PruneColumns(parentUsedCols []*expression.Column) { +func (p *LogicalSelection) PruneColumns(parentUsedCols []*expression.Column) { child := p.children[0].(LogicalPlan) for _, cond := range p.Conditions { parentUsedCols = append(parentUsedCols, expression.ExtractColumns(cond)...) diff --git a/plan/decorrelate.go b/plan/decorrelate.go index 6f27905cce501..b5de9dc2055a9 100644 --- a/plan/decorrelate.go +++ b/plan/decorrelate.go @@ -95,7 +95,7 @@ func (s *decorrelateSolver) optimize(p LogicalPlan, _ context.Context) (LogicalP outerPlan.SetParents(join) join.self = join p = join - } else if sel, ok := innerPlan.(*Selection); ok { + } else if sel, ok := innerPlan.(*LogicalSelection); ok { // If the inner plan is a selection, we add this condition to join predicates. // Notice that no matter what kind of join is, it's always right. newConds := make([]expression.Expression, 0, len(sel.Conditions)) diff --git a/plan/eliminate_projection.go b/plan/eliminate_projection.go index ea2cdac9da630..615c995bc7675 100644 --- a/plan/eliminate_projection.go +++ b/plan/eliminate_projection.go @@ -129,7 +129,7 @@ func (pe *projectionEliminater) eliminate(p LogicalPlan, replace map[string]*exp setParentAndChildren(p, children...) switch p.(type) { - case *Sort, *TopN, *Limit, *Selection, *MaxOneRow, *Update, *SelectLock: + case *Sort, *TopN, *Limit, *LogicalSelection, *MaxOneRow, *Update, *SelectLock: p.SetSchema(p.Children()[0].Schema()) case *LogicalJoin, *LogicalApply: var joinTp JoinType @@ -239,7 +239,7 @@ func (p *LogicalAggregation) replaceExprColumns(replace map[string]*expression.C p.collectGroupByColumns() } -func (p *Selection) replaceExprColumns(replace map[string]*expression.Column) { +func (p *LogicalSelection) replaceExprColumns(replace map[string]*expression.Column) { for _, expr := range p.Conditions { resolveExprAndReplace(expr, replace) } diff --git a/plan/explain.go b/plan/explain.go index c17858ec29b59..b847aa9519ed8 100644 --- a/plan/explain.go +++ b/plan/explain.go @@ -143,7 +143,7 @@ func (p *PhysicalUnionScan) ExplainInfo() string { } // ExplainInfo implements PhysicalPlan interface. -func (p *Selection) ExplainInfo() string { +func (p *PhysicalSelection) ExplainInfo() string { return string(expression.ExplainExpressionList(p.Conditions)) } diff --git a/plan/gen_physical_plans.go b/plan/gen_physical_plans.go index 25dc310d06798..bbe1a3468e3db 100644 --- a/plan/gen_physical_plans.go +++ b/plan/gen_physical_plans.go @@ -267,3 +267,12 @@ func (p *LogicalAggregation) generatePhysicalPlans() []PhysicalPlan { return aggs } + +func (p *LogicalSelection) generatePhysicalPlans() []PhysicalPlan { + sel := PhysicalSelection{ + Conditions: p.Conditions, + }.init(p.ctx) + sel.profile = p.profile + sel.SetSchema(p.Schema()) + return []PhysicalPlan{sel} +} diff --git a/plan/initialize.go b/plan/initialize.go index f0a888b724e67..8263995076b1d 100644 --- a/plan/initialize.go +++ b/plan/initialize.go @@ -109,9 +109,14 @@ func (p LogicalApply) init(ctx context.Context) *LogicalApply { return &p } -func (p Selection) init(ctx context.Context) *Selection { +func (p LogicalSelection) init(ctx context.Context) *LogicalSelection { p.basePlan = newBasePlan(TypeSel, ctx, &p) p.baseLogicalPlan = newBaseLogicalPlan(p.basePlan) + return &p +} + +func (p PhysicalSelection) init(ctx context.Context) *PhysicalSelection { + p.basePlan = newBasePlan(TypeSel, ctx, &p) p.basePhysicalPlan = newBasePhysicalPlan(p.basePlan) return &p } diff --git a/plan/logical_plan_builder.go b/plan/logical_plan_builder.go index 7d00bd5a1f2a6..6211b4f0c9c26 100644 --- a/plan/logical_plan_builder.go +++ b/plan/logical_plan_builder.go @@ -405,7 +405,7 @@ func (b *planBuilder) buildSelection(p LogicalPlan, where ast.ExprNode, AggMappe } conditions := splitWhere(where) expressions := make([]expression.Expression, 0, len(conditions)) - selection := Selection{}.init(b.ctx) + selection := LogicalSelection{}.init(b.ctx) for _, cond := range conditions { expr, np, err := b.rewrite(cond, p, AggMapper, false) if err != nil { diff --git a/plan/logical_plans.go b/plan/logical_plans.go index a3c01bab57e6e..2b7b74c00c149 100644 --- a/plan/logical_plans.go +++ b/plan/logical_plans.go @@ -27,7 +27,7 @@ var ( _ LogicalPlan = &LogicalJoin{} _ LogicalPlan = &LogicalAggregation{} _ LogicalPlan = &Projection{} - _ LogicalPlan = &Selection{} + _ LogicalPlan = &LogicalSelection{} _ LogicalPlan = &LogicalApply{} _ LogicalPlan = &Exists{} _ LogicalPlan = &MaxOneRow{} @@ -206,11 +206,10 @@ func (p *LogicalAggregation) extractCorrelatedCols() []*expression.CorrelatedCol return corCols } -// Selection means a filter. -type Selection struct { +// LogicalSelection represents a where or having predicate. +type LogicalSelection struct { *basePlan baseLogicalPlan - basePhysicalPlan // Originally the WHERE or ON condition is parsed into a single expression, // but after we converted to CNF(Conjunctive normal form), it can be @@ -218,7 +217,7 @@ type Selection struct { Conditions []expression.Expression } -func (p *Selection) extractCorrelatedCols() []*expression.CorrelatedColumn { +func (p *LogicalSelection) extractCorrelatedCols() []*expression.CorrelatedColumn { corCols := p.baseLogicalPlan.extractCorrelatedCols() for _, cond := range p.Conditions { corCols = append(corCols, extractCorColumns(cond)...) diff --git a/plan/physical_plan_builder.go b/plan/physical_plan_builder.go index 3c57bcc583e23..1de339dc40921 100644 --- a/plan/physical_plan_builder.go +++ b/plan/physical_plan_builder.go @@ -384,7 +384,7 @@ func (p *DataSource) tryToGetMemTask(prop *requiredProp) (task task, err error) memTable.profile = p.profile var retPlan PhysicalPlan = memTable if len(p.pushedDownConds) > 0 { - sel := Selection{ + sel := PhysicalSelection{ Conditions: p.pushedDownConds, }.init(p.ctx) sel.SetSchema(p.schema) @@ -675,7 +675,7 @@ func (is *PhysicalIndexScan) addPushedDownSelection(copTask *copTask, p *DataSou for _, cond := range indexConds { condsClone = append(condsClone, cond.Clone()) } - indexSel := Selection{Conditions: condsClone}.init(is.ctx) + indexSel := PhysicalSelection{Conditions: condsClone}.init(is.ctx) indexSel.SetSchema(is.schema) indexSel.SetChildren(is) indexSel.profile = p.getStatsProfileByFilter(append(is.AccessCondition, indexConds...)) @@ -686,7 +686,7 @@ func (is *PhysicalIndexScan) addPushedDownSelection(copTask *copTask, p *DataSou } if tableConds != nil { copTask.finishIndexPlan() - tableSel := Selection{Conditions: tableConds}.init(is.ctx) + tableSel := PhysicalSelection{Conditions: tableConds}.init(is.ctx) tableSel.SetSchema(copTask.tablePlan.Schema()) tableSel.SetChildren(copTask.tablePlan) tableSel.profile = p.profile @@ -863,7 +863,7 @@ func (p *DataSource) convertToTableScan(prop *requiredProp) (task task, err erro func (ts *PhysicalTableScan) addPushedDownSelection(copTask *copTask, profile *statsProfile, expectedCnt float64) { // Add filter condition to table plan now. if len(ts.filterCondition) > 0 { - sel := Selection{Conditions: ts.filterCondition}.init(ts.ctx) + sel := PhysicalSelection{Conditions: ts.filterCondition}.init(ts.ctx) sel.SetSchema(ts.schema) sel.SetChildren(ts) sel.profile = profile @@ -884,6 +884,11 @@ func (p *basePhysicalPlan) getChildrenPossibleProps(prop *requiredProp) [][]*req return [][]*requiredProp{props} } +func (p *PhysicalSelection) getChildrenPossibleProps(prop *requiredProp) [][]*requiredProp { + p.expectedCnt = prop.expectedCnt + return [][]*requiredProp{{prop}} +} + func (p *PhysicalHashJoin) getChildrenPossibleProps(prop *requiredProp) [][]*requiredProp { p.expectedCnt = prop.expectedCnt if !prop.isEmpty() { diff --git a/plan/physical_plans.go b/plan/physical_plans.go index 5391644ebf281..833050fa75ec3 100644 --- a/plan/physical_plans.go +++ b/plan/physical_plans.go @@ -24,7 +24,7 @@ import ( ) var ( - _ PhysicalPlan = &Selection{} + _ PhysicalPlan = &PhysicalSelection{} _ PhysicalPlan = &Projection{} _ PhysicalPlan = &Exists{} _ PhysicalPlan = &MaxOneRow{} @@ -387,11 +387,18 @@ func (p *PhysicalMergeJoin) Copy() PhysicalPlan { return &np } +// PhysicalSelection represents a filter. +type PhysicalSelection struct { + *basePlan + basePhysicalPlan + + Conditions []expression.Expression +} + // Copy implements the PhysicalPlan Copy interface. -func (p *Selection) Copy() PhysicalPlan { +func (p *PhysicalSelection) Copy() PhysicalPlan { np := *p np.basePlan = p.basePlan.copy() - np.baseLogicalPlan = newBaseLogicalPlan(np.basePlan) np.basePhysicalPlan = newBasePhysicalPlan(np.basePlan) return &np } @@ -543,7 +550,7 @@ func buildJoinSchema(joinType JoinType, join Plan, outerID int) *expression.Sche func buildSchema(p PhysicalPlan) { switch x := p.(type) { - case *Limit, *TopN, *Sort, *Selection, *MaxOneRow, *SelectLock: + case *Limit, *TopN, *Sort, *PhysicalSelection, *MaxOneRow, *SelectLock: p.SetSchema(p.Children()[0].Schema()) case *PhysicalIndexJoin: p.SetSchema(buildJoinSchema(x.JoinType, p, x.outerIndex)) diff --git a/plan/plan_to_pb.go b/plan/plan_to_pb.go index 96eb5c192f38c..1ba1924e2076e 100644 --- a/plan/plan_to_pb.go +++ b/plan/plan_to_pb.go @@ -27,7 +27,7 @@ import ( // ToPB implements PhysicalPlan ToPB interface. func (p *basePhysicalPlan) ToPB(_ context.Context) (*tipb.Executor, error) { - return nil, errors.Errorf("plan %d fails converts to PB", p.basePlan.id) + return nil, errors.Errorf("plan %s fails converts to PB", p.basePlan.ExplainID()) } // ToPB implements PhysicalPlan ToPB interface. @@ -44,7 +44,7 @@ func (p *PhysicalAggregation) ToPB(ctx context.Context) (*tipb.Executor, error) } // ToPB implements PhysicalPlan ToPB interface. -func (p *Selection) ToPB(ctx context.Context) (*tipb.Executor, error) { +func (p *PhysicalSelection) ToPB(ctx context.Context) (*tipb.Executor, error) { sc := ctx.GetSessionVars().StmtCtx client := ctx.GetClient() selExec := &tipb.Selection{ diff --git a/plan/planbuilder.go b/plan/planbuilder.go index 246257e1874b6..9761c896a6083 100644 --- a/plan/planbuilder.go +++ b/plan/planbuilder.go @@ -623,7 +623,7 @@ func (b *planBuilder) buildShow(show *ast.ShowStmt) Plan { } } if len(conditions) != 0 { - sel := Selection{Conditions: conditions}.init(b.ctx) + sel := LogicalSelection{Conditions: conditions}.init(b.ctx) setParentAndChildren(sel, p) sel.SetSchema(p.Schema()) resultPlan = sel diff --git a/plan/predicate_push_down.go b/plan/predicate_push_down.go index 7ed72063170ec..62235f3e8f2a4 100644 --- a/plan/predicate_push_down.go +++ b/plan/predicate_push_down.go @@ -30,7 +30,7 @@ func (s *ppdSolver) optimize(lp LogicalPlan, _ context.Context) (LogicalPlan, er func addSelection(p Plan, child LogicalPlan, conditions []expression.Expression) { conditions = expression.PropagateConstant(p.context(), conditions) - selection := Selection{Conditions: conditions}.init(p.context()) + selection := LogicalSelection{Conditions: conditions}.init(p.context()) selection.SetSchema(child.Schema().Clone()) replaceChild(p, child, selection) selection.SetChildren(child) @@ -52,7 +52,7 @@ func (p *baseLogicalPlan) PredicatePushDown(predicates []expression.Expression) } // PredicatePushDown implements LogicalPlan PredicatePushDown interface. -func (p *Selection) PredicatePushDown(predicates []expression.Expression) ([]expression.Expression, LogicalPlan) { +func (p *LogicalSelection) PredicatePushDown(predicates []expression.Expression) ([]expression.Expression, LogicalPlan) { retConditions, child := p.children[0].(LogicalPlan).PredicatePushDown(append(p.Conditions, predicates...)) if len(retConditions) > 0 { p.Conditions = expression.PropagateConstant(p.ctx, retConditions) diff --git a/plan/property_cols_prune.go b/plan/property_cols_prune.go index 7ef62a7c1dce1..39e665c4a08ff 100644 --- a/plan/property_cols_prune.go +++ b/plan/property_cols_prune.go @@ -35,7 +35,7 @@ func (p *DataSource) preparePossibleProperties() (result [][]*expression.Column) return } -func (p *Selection) preparePossibleProperties() (result [][]*expression.Column) { +func (p *LogicalSelection) preparePossibleProperties() (result [][]*expression.Column) { return p.children[0].(LogicalPlan).preparePossibleProperties() } diff --git a/plan/resolve_indices.go b/plan/resolve_indices.go index 8bb7449a057d7..917549715ef6f 100644 --- a/plan/resolve_indices.go +++ b/plan/resolve_indices.go @@ -140,7 +140,7 @@ func (p *PhysicalIndexLookUpReader) ResolveIndices() { } // ResolveIndices implements Plan interface. -func (p *Selection) ResolveIndices() { +func (p *PhysicalSelection) ResolveIndices() { p.basePlan.ResolveIndices() for _, expr := range p.Conditions { expr.ResolveIndices(p.children[0].Schema()) diff --git a/plan/stats.go b/plan/stats.go index 9824487b12ad8..8b79dfdde14de 100644 --- a/plan/stats.go +++ b/plan/stats.go @@ -100,7 +100,7 @@ func (p *DataSource) prepareStatsProfile() *statsProfile { return p.profile } -func (p *Selection) prepareStatsProfile() *statsProfile { +func (p *LogicalSelection) prepareStatsProfile() *statsProfile { childProfile := p.children[0].(LogicalPlan).prepareStatsProfile() p.profile = childProfile.collapse(selectionFactor) return p.profile diff --git a/plan/stringer.go b/plan/stringer.go index 93712f899cede..c2112bd94c062 100644 --- a/plan/stringer.go +++ b/plan/stringer.go @@ -150,7 +150,9 @@ func toString(in Plan, strs []string, idxs []int) ([]string, []int) { } else { str = fmt.Sprintf("DataScan(%s)", x.tableInfo.Name) } - case *Selection: + case *LogicalSelection: + str = fmt.Sprintf("Sel(%s)", x.Conditions) + case *PhysicalSelection: str = fmt.Sprintf("Sel(%s)", x.Conditions) case *Projection: str = "Projection" diff --git a/plan/task.go b/plan/task.go index e380395eeb623..568c1dc91772e 100644 --- a/plan/task.go +++ b/plan/task.go @@ -431,7 +431,7 @@ func (p *Union) attach2Task(tasks ...task) task { return newTask } -func (sel *Selection) attach2Task(tasks ...task) task { +func (sel *PhysicalSelection) attach2Task(tasks ...task) task { if tasks[0].invalid() { return invalidTask } diff --git a/statistics/selectivity_test.go b/statistics/selectivity_test.go index 74caf5904e95c..9c9fe46600387 100644 --- a/statistics/selectivity_test.go +++ b/statistics/selectivity_test.go @@ -169,16 +169,7 @@ func (s *testSelectivitySuite) TestSelectivity(c *C) { c.Assert(err, IsNil, comment) p, err := plan.BuildLogicalPlan(ctx, stmts[0], is) c.Assert(err, IsNil, Commentf("error %v, for building plan, expr %s", err, tt.exprs)) - var sel *plan.Selection - for _, child := range p.Children() { - p, ok := child.(*plan.Selection) - if ok { - sel = p - break - } - } - c.Assert(sel, NotNil, comment) - ratio, err := statsTbl.Selectivity(ctx, sel.Conditions) + ratio, err := statsTbl.Selectivity(ctx, p.Children()[0].(*plan.LogicalSelection).Conditions) c.Assert(err, IsNil, comment) c.Assert(math.Abs(ratio-tt.selectivity) < eps, IsTrue, comment) } diff --git a/util/ranger/ranger_test.go b/util/ranger/ranger_test.go index 6a2b9898697fb..0a1fe81b2f99f 100644 --- a/util/ranger/ranger_test.go +++ b/util/ranger/ranger_test.go @@ -308,15 +308,7 @@ func (s *testRangerSuite) TestTableRange(c *C) { c.Assert(err, IsNil, Commentf("error %v, for resolve name, expr %s", err, tt.exprStr)) p, err := plan.BuildLogicalPlan(ctx, stmts[0], is) c.Assert(err, IsNil, Commentf("error %v, for build plan, expr %s", err, tt.exprStr)) - var selection *plan.Selection - for _, child := range p.Children() { - p, ok := child.(*plan.Selection) - if ok { - selection = p - break - } - } - c.Assert(selection, NotNil, Commentf("expr:%v", tt.exprStr)) + selection := p.Children()[0].(*plan.LogicalSelection) conds := make([]expression.Expression, 0, len(selection.Conditions)) for _, cond := range selection.Conditions { conds = append(conds, expression.PushDownNot(cond, false, ctx)) @@ -498,14 +490,7 @@ func (s *testRangerSuite) TestIndexRange(c *C) { c.Assert(err, IsNil, Commentf("error %v, for resolve name, expr %s", err, tt.exprStr)) p, err := plan.BuildLogicalPlan(ctx, stmts[0], is) c.Assert(err, IsNil, Commentf("error %v, for build plan, expr %s", err, tt.exprStr)) - var selection *plan.Selection - for _, child := range p.Children() { - p, ok := child.(*plan.Selection) - if ok { - selection = p - break - } - } + selection := p.Children()[0].(*plan.LogicalSelection) tbl := selection.Children()[0].(*plan.DataSource).TableInfo() c.Assert(selection, NotNil, Commentf("expr:%v", tt.exprStr)) conds := make([]expression.Expression, 0, len(selection.Conditions)) @@ -749,15 +734,7 @@ func (s *testRangerSuite) TestColumnRange(c *C) { c.Assert(err, IsNil, Commentf("error %v, for resolve name, expr %s", err, tt.exprStr)) p, err := plan.BuildLogicalPlan(ctx, stmts[0], is) c.Assert(err, IsNil, Commentf("error %v, for build plan, expr %s", err, tt.exprStr)) - var sel *plan.Selection - for _, child := range p.Children() { - plan, ok := child.(*plan.Selection) - if ok { - sel = plan - break - } - } - c.Assert(sel, NotNil, Commentf("expr:%v", tt.exprStr)) + sel := p.Children()[0].(*plan.LogicalSelection) ds, ok := sel.Children()[0].(*plan.DataSource) c.Assert(ok, IsTrue, Commentf("expr:%v", tt.exprStr)) conds := make([]expression.Expression, 0, len(sel.Conditions))