コード例 #1
0
ファイル: join.go プロジェクト: ninefive/tidb
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
}
コード例 #2
0
ファイル: join.go プロジェクト: studygolang/tidb
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()))
	}

}
コード例 #3
0
ファイル: update.go プロジェクト: botvs/tidb
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
}
コード例 #4
0
ファイル: select.go プロジェクト: nengwang/tidb
// 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
}
コード例 #5
0
ファイル: union.go プロジェクト: kevinhuo88888/tidb
// 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
}