func (r *JoinRset) buildSourcePlan(ctx context.Context, t *TableSource) (plan.Plan, []*field.ResultField, error) { var ( src interface{} tr *TableRset err error ) switch s := t.Source.(type) { case table.Ident: fullIdent := s.Full(ctx) tr, err = newTableRset(fullIdent.Schema.O, fullIdent.Name.O) if err != nil { return nil, nil, errors.Trace(err) } src = tr if t.Name == "" { qualifiedTableName := tr.Schema + "." + tr.Name if r.tableNames[qualifiedTableName] { return nil, nil, errors.Errorf("%s: duplicate name %s", r.String(), s) } r.tableNames[qualifiedTableName] = true } case stmt.Statement: src = s default: return nil, nil, errors.Errorf("invalid table source %T", t.Source) } var p plan.Plan switch x := src.(type) { case plan.Planner: if p, err = x.Plan(ctx); err != nil { return nil, nil, errors.Trace(err) } case plan.Plan: p = x default: return nil, nil, errors.Errorf("invalid table source %T, no Plan interface", t.Source) } var fields []*field.ResultField dupNames := make(map[string]struct{}, len(p.GetFields())) for _, nf := range p.GetFields() { f := nf.Clone() if t.Name != "" { f.TableName = t.Name } // duplicate column name in one table is not allowed. name := strings.ToLower(f.Name) if _, ok := dupNames[name]; ok { return nil, nil, errors.Errorf("Duplicate column name '%s'", name) } dupNames[name] = struct{}{} fields = append(fields, f) } return p, fields, nil }
func (r *JoinPlan) filterNode(ctx context.Context, expr expression.Expression, node plan.Plan) (plan.Plan, bool, error) { if node == nil { return r, false, nil } e2 := expr.Clone() return node.Filter(ctx, e2) }
func (r *JoinPlan) findMatchedRows(ctx context.Context, row *plan.Row, p plan.Plan, right bool) (err error) { r.cursor = 0 r.matchedRows = nil p.Close() for { var cmpRow *plan.Row cmpRow, err = p.Next(ctx) if err != nil { return errors.Trace(err) } if cmpRow == nil { break } // Do append(s1, s2) safely. Sometime the s1 capability is larger than its real length, so // multi append may overwrite last valid data, e.g, // s1 = make([]interface{}, 0, 1) // s = append(s1, []interface{}{1}) // ss = append(ss, s) // s = append(s1, []interface{}{2}) // ss = append(ss, s) // We will see that ss only contains 2. joined := make([]interface{}, 0, len(cmpRow.Data)+len(row.Data)) if right { joined = append(append(joined, cmpRow.Data...), row.Data...) } else { joined = append(append(joined, row.Data...), cmpRow.Data...) } r.evalArgs[expression.ExprEvalIdentFunc] = func(name string) (interface{}, error) { return GetIdentValue(name, r.Fields, joined, field.DefaultFieldFlag) } var b bool b, err = expression.EvalBoolExpr(ctx, r.On, r.evalArgs) if err != nil { return errors.Trace(err) } if b { cmpRow.Data = joined keys := make([]*plan.RowKeyEntry, 0, len(row.RowKeys)+len(cmpRow.RowKeys)) cmpRow.RowKeys = append(append(keys, row.RowKeys...), cmpRow.RowKeys...) r.matchedRows = append(r.matchedRows, cmpRow) } } if len(r.matchedRows) == 0 { if right { leftLen := len(r.Fields) - len(r.Right.GetFields()) row.Data = append(make([]interface{}, leftLen), row.Data...) } else { rightLen := len(r.Fields) - len(r.Left.GetFields()) row.Data = append(row.Data, make([]interface{}, rightLen)...) } r.matchedRows = append(r.matchedRows, row) } return nil }
func (r *JoinPlan) explainNode(w format.Formatter, node plan.Plan) { sel := !isTableOrIndex(node) if sel { w.Format("┌Iterate all rows of virtual table\n") } node.Explain(w) if sel { w.Format("└Output field names %v\n", field.RFQNames(node.GetFields())) } }
func (r *JoinPlan) findMatchedRows(ctx context.Context, row *plan.Row, right bool) (err error) { var p plan.Plan if right { p = r.Left } else { p = r.Right } r.cursor = 0 r.matchedRows = nil p.Close() for { var cmpRow *plan.Row cmpRow, err = p.Next(ctx) if err != nil { return errors.Trace(err) } if cmpRow == nil { break } var joined []interface{} if right { joined = append(cmpRow.Data, row.Data...) } else { joined = append(row.Data, cmpRow.Data...) } r.evalArgs[expressions.ExprEvalIdentFunc] = func(name string) (interface{}, error) { return GetIdentValue(name, r.Fields, joined, field.DefaultFieldFlag) } var b bool b, err = expressions.EvalBoolExpr(ctx, r.On, r.evalArgs) if err != nil { return errors.Trace(err) } if b { cmpRow.Data = joined cmpRow.RowKeys = append(row.RowKeys, cmpRow.RowKeys...) r.matchedRows = append(r.matchedRows, cmpRow) } } if len(r.matchedRows) == 0 { if right { leftLen := len(r.Fields) - len(r.Right.GetFields()) row.Data = append(make([]interface{}, leftLen), row.Data...) } else { rightLen := len(r.Fields) - len(r.Left.GetFields()) row.Data = append(row.Data, make([]interface{}, rightLen)...) } r.matchedRows = append(r.matchedRows, row) } return nil }
func (v *explainVisitor) explain(p plan.Plan) { switch x := p.(type) { case *plan.TableScan: v.entries = append(v.entries, v.newEntryForTableScan(x)) case *plan.IndexScan: v.entries = append(v.entries, v.newEntryForIndexScan(x)) case *plan.Sort: v.sort = true } for _, c := range p.GetChildren() { v.explain(c) } }
func (s *UpdateStmt) plan(ctx context.Context) (plan.Plan, error) { var ( r plan.Plan err error ) if s.TableRefs != nil { r, err = s.TableRefs.Plan(ctx) if err != nil { return nil, errors.Trace(err) } } if s.Where != nil { r, err = (&rsets.WhereRset{Expr: s.Where, Src: r}).Plan(ctx) if err != nil { return nil, errors.Trace(err) } } if s.Order != nil { s.Order.Src = r r, err = s.Order.Plan(ctx) if err != nil { return nil, errors.Trace(err) } } if s.Limit != nil { s.Limit.Src = r r, err = s.Limit.Plan(ctx) if err != nil { return nil, errors.Trace(err) } } visitor := rsets.NewFromIdentVisitor(r.GetFields(), rsets.UpdateClause) for i := range s.List { e, err := s.List[i].Expr.Accept(visitor) if err != nil { return nil, errors.Trace(err) } s.List[i].Expr = e } return r, nil }
func (e *ExplainExec) prepareExplainInfo(p plan.Plan, parent plan.Plan) error { for _, child := range p.GetChildren() { err := e.prepareExplainInfo(child, p) if err != nil { return errors.Trace(err) } } explain, err := json.MarshalIndent(p, "", " ") if err != nil { return errors.Trace(err) } parentStr := "" if parent != nil { parentStr = parent.GetID() } row := &Row{ Data: types.MakeDatums(p.GetID(), string(explain), parentStr), } e.rows = append(e.rows, row) return nil }
// Plan implements the plan.Planner interface. // The whole phase for select is // `from -> where -> lock -> group by -> having -> select fields -> distinct -> order by -> limit -> final` func (s *SelectStmt) Plan(ctx context.Context) (plan.Plan, error) { var ( r plan.Plan err error ) if s.From != nil { r, err = s.From.Plan(ctx) if err != nil { return nil, err } } else if s.Fields != nil { // Only evaluate fields values. fr := &rsets.SelectFromDualRset{Fields: s.Fields} r, err = fr.Plan(ctx) if err != nil { return nil, err } } // Put RowStackFromPlan here so that we can catch the origin from data after above FROM phase. r = &plans.RowStackFromPlan{Src: r} if w := s.Where; w != nil { r, err = (&rsets.WhereRset{Expr: w.Expr, Src: r}).Plan(ctx) if err != nil { return nil, err } } lock := s.Lock if variable.ShouldAutocommit(ctx) { // Locking of rows for update using SELECT FOR UPDATE only applies when autocommit // is disabled (either by beginning transaction with START TRANSACTION or by setting // autocommit to 0. If autocommit is enabled, the rows matching the specification are not locked. // See: https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html lock = coldef.SelectLockNone } r = &plans.SelectLockPlan{Src: r, Lock: lock} if err := s.checkOneColumn(ctx); err != nil { return nil, errors.Trace(err) } // Get select list for futher field values evaluation. selectList, err := plans.ResolveSelectList(s.Fields, r.GetFields()) if err != nil { return nil, errors.Trace(err) } var groupBy []expression.Expression if s.GroupBy != nil { groupBy = s.GroupBy.By } if s.Having != nil { // `having` may contain aggregate functions, and we will add this to hidden fields. if err = s.Having.CheckAndUpdateSelectList(selectList, groupBy, r.GetFields()); err != nil { return nil, errors.Trace(err) } } if s.OrderBy != nil { // `order by` may contain aggregate functions, and we will add this to hidden fields. if err = s.OrderBy.CheckAndUpdateSelectList(selectList, r.GetFields()); err != nil { return nil, errors.Trace(err) } } switch { case !rsets.HasAggFields(selectList.Fields) && s.GroupBy == nil: // If no group by and no aggregate functions, we will use SelectFieldsPlan. if r, err = (&rsets.SelectFieldsRset{Src: r, SelectList: selectList, }).Plan(ctx); err != nil { return nil, err } default: if r, err = (&rsets.GroupByRset{By: groupBy, Src: r, SelectList: selectList, }).Plan(ctx); err != nil { return nil, err } } if s := s.Having; s != nil { if r, err = (&rsets.HavingRset{ Src: r, Expr: s.Expr}).Plan(ctx); err != nil { return nil, err } } if s.Distinct { r = &plans.DistinctDefaultPlan{Src: r, SelectList: selectList} } if s := s.OrderBy; s != nil { if r, err = (&rsets.OrderByRset{By: s.By, Src: r, SelectList: selectList, }).Plan(ctx); err != nil { return nil, err } } if s := s.Offset; s != nil { r = &plans.OffsetDefaultPlan{Count: s.Count, Src: r, Fields: r.GetFields()} } if s := s.Limit; s != nil { r = &plans.LimitDefaultPlan{Count: s.Count, Src: r, Fields: r.GetFields()} } r = &plans.SelectFinalPlan{Src: r, SelectList: selectList} return r, nil }
// Plan implements the plan.Planner interface. func (s *UnionStmt) Plan(ctx context.Context) (plan.Plan, error) { srcs := make([]plan.Plan, 0, len(s.Selects)) columnCount := 0 for _, s := range s.Selects { p, err := s.Plan(ctx) if err != nil { return nil, err } if columnCount > 0 && columnCount != len(p.GetFields()) { return nil, errors.New("The used SELECT statements have a different number of columns") } columnCount = len(p.GetFields()) srcs = append(srcs, p) } for i := len(s.Distincts) - 1; i >= 0; i-- { if s.Distincts[i] { // distinct overwrites all previous all // e.g, select * from t1 union all select * from t2 union distinct select * from t3. // The distinct will overwrite all for t1 and t2. i-- for ; i >= 0; i-- { s.Distincts[i] = true } break } } fields := srcs[0].GetFields() selectList := &plans.SelectList{} selectList.ResultFields = make([]*field.ResultField, len(fields)) selectList.HiddenFieldOffset = len(fields) // Union uses first select return column names and ignores table name. // We only care result name and type here. for i, f := range fields { nf := &field.ResultField{} nf.Name = f.Name nf.FieldType = f.FieldType selectList.ResultFields[i] = nf } var ( r plan.Plan err error ) r = &plans.UnionPlan{Srcs: srcs, Distincts: s.Distincts, RFields: selectList.ResultFields} if s := s.OrderBy; s != nil { if r, err = (&rsets.OrderByRset{By: s.By, Src: r, SelectList: selectList, }).Plan(ctx); err != nil { return nil, err } } if s := s.Offset; s != nil { r = &plans.OffsetDefaultPlan{Count: s.Count, Src: r, Fields: r.GetFields()} } if s := s.Limit; s != nil { r = &plans.LimitDefaultPlan{Count: s.Count, Src: r, Fields: r.GetFields()} } return r, nil }