Ejemplo n.º 1
0
func runStmt(ctx context.Context, s stmt.Statement, args ...interface{}) (rset.Recordset, error) {
	var err error
	var rs rset.Recordset
	// before every execution, we must clear affectedrows.
	variable.GetSessionVars(ctx).SetAffectedRows(0)
	switch s.(type) {
	case *stmts.PreparedStmt:
		ps := s.(*stmts.PreparedStmt)
		return runPreparedStmt(ctx, ps)
	case *stmts.ExecuteStmt:
		es := s.(*stmts.ExecuteStmt)
		rs, err = runExecute(ctx, es, args...)
		if err != nil {
			return nil, errors.Trace(err)
		}
	default:
		if s.IsDDL() {
			err = ctx.FinishTxn(false)
			if err != nil {
				return nil, errors.Trace(err)
			}
		}
		stmt.BindExecArgs(ctx, args)
		rs, err = s.Exec(ctx)
		stmt.ClearExecArgs(ctx)
	}
	// MySQL DDL should be auto-commit
	if err == nil && (s.IsDDL() || variable.ShouldAutocommit(ctx)) {
		err = ctx.FinishTxn(false)
	}
	return rs, errors.Trace(err)
}
Ejemplo n.º 2
0
// 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
}