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) 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 (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 }
// 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 }