// If forceNew is true, GetTxn() must return a new transaction. // In this situation, if current transaction is still in progress, // there will be an implicit commit and create a new transaction. func (s *session) GetTxn(forceNew bool) (kv.Transaction, error) { var err error if s.txn == nil { s.resetHistory() s.txn, err = s.store.Begin() if err != nil { return nil, err } if !variable.IsAutocommit(s) { variable.GetSessionVars(s).SetStatusFlag(mysql.ServerStatusInTrans, true) } log.Infof("New txn:%s in session:%d", s.txn, s.sid) return s.txn, nil } if forceNew { err = s.txn.Commit() variable.GetSessionVars(s).SetStatusFlag(mysql.ServerStatusInTrans, false) if err != nil { return nil, err } s.resetHistory() s.txn, err = s.store.Begin() if err != nil { return nil, err } if !variable.IsAutocommit(s) { variable.GetSessionVars(s).SetStatusFlag(mysql.ServerStatusInTrans, true) } log.Warnf("Force new txn:%s in session:%d", s.txn, s.sid) } return s.txn, nil }
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.IsAutocommit(ctx)) { err = ctx.FinishTxn(false) } return rs, errors.Trace(err) }
// 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.FieldRset{Fields: s.Fields} r, err = fr.Plan(ctx) if err != nil { return nil, err } } 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.IsAutocommit(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, err = (&rsets.SelectLockRset{Src: r, Lock: lock}).Plan(ctx) if err != nil { return nil, 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 { if r, err = (&rsets.DistinctRset{Src: r, SelectList: selectList}).Plan(ctx); err != nil { return nil, err } } 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 { if r, err = (&rsets.OffsetRset{Count: s.Count, Src: r}).Plan(ctx); err != nil { return nil, err } } if s := s.Limit; s != nil { if r, err = (&rsets.LimitRset{Count: s.Count, Src: r}).Plan(ctx); err != nil { return nil, err } } if r, err = (&rsets.SelectFinalRset{Src: r, SelectList: selectList}).Plan(ctx); err != nil { return nil, err } return r, nil }