// Exec implements the ast.Statement Exec interface. // This function builds an Executor from a plan. If the Executor doesn't return result, // like the INSERT, UPDATE statements, it executes in this function, if the Executor returns // result, execution is done after this function returns, in the returned ast.RecordSet Next method. func (a *statement) Exec(ctx context.Context) (ast.RecordSet, error) { b := newExecutorBuilder(ctx, a.is) e := b.build(a.plan) if b.err != nil { return nil, errors.Trace(b.err) } // ExecuteExec is not a real Executor, we only use it to build another Executor from a prepared statement. if executorExec, ok := e.(*ExecuteExec); ok { err := executorExec.Build() if err != nil { return nil, errors.Trace(err) } e = executorExec.StmtExec } // Fields or Schema are only used for statements that return result set. if len(e.Fields()) == 0 && len(e.Schema()) == 0 { // Check if "tidb_snapshot" is set for the write executors. // In history read mode, we can not do write operations. switch e.(type) { case *DeleteExec, *InsertExec, *UpdateExec, *ReplaceExec, *LoadData, *DDLExec: snapshotTS := variable.GetSnapshotTS(ctx) if snapshotTS != 0 { return nil, errors.New("Can not execute write statement when 'tidb_snapshot' is set.") } } defer e.Close() for { row, err := e.Next() if err != nil { return nil, errors.Trace(err) } // Even though there isn't any result set, the row is still used to indicate if there is // more work to do. // For example, the UPDATE statement updates a single row on a Next call, we keep calling Next until // There is no more rows to update. if row == nil { return nil, nil } } } fs := e.Fields() for _, f := range fs { if len(f.ColumnAsName.O) == 0 { f.ColumnAsName = f.Column.Name } } return &recordSet{ executor: e, fields: fs, schema: e.Schema(), }, nil }
func (b *executorBuilder) getStartTS() uint64 { startTS := variable.GetSnapshotTS(b.ctx) if startTS == 0 { txn, err := b.ctx.GetTxn(false) if err != nil { b.err = errors.Trace(err) return 0 } startTS = txn.StartTS() } return startTS }
func (s *testSuite) TestHistoryRead(c *C) { defer testleak.AfterTest(c)() tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test") tk.MustExec("drop table if exists history_read") tk.MustExec("create table history_read (a int)") tk.MustExec("insert history_read values (1)") curVer1, _ := s.store.CurrentVersion() time.Sleep(time.Millisecond) snapshotTime := time.Now() time.Sleep(time.Millisecond) curVer2, _ := s.store.CurrentVersion() tk.MustExec("insert history_read values (2)") tk.MustQuery("select * from history_read").Check(testkit.Rows("1", "2")) tk.MustExec("set @@tidb_snapshot = '" + snapshotTime.Format("2006-01-02 15:04:05.999999") + "'") ctx := tk.Se.(context.Context) snapshotTS := variable.GetSnapshotTS(ctx) c.Assert(snapshotTS, Greater, curVer1.Ver) c.Assert(snapshotTS, Less, curVer2.Ver) tk.MustQuery("select * from history_read").Check(testkit.Rows("1")) _, err := tk.Exec("insert history_read values (2)") c.Assert(err, NotNil) _, err = tk.Exec("update history_read set a = 3 where a = 1") c.Assert(err, NotNil) _, err = tk.Exec("delete from history_read where a = 1") c.Assert(err, NotNil) tk.MustExec("set @@tidb_snapshot = ''") tk.MustQuery("select * from history_read").Check(testkit.Rows("1", "2")) tk.MustExec("insert history_read values (3)") tk.MustExec("update history_read set a = 4 where a = 3") tk.MustExec("delete from history_read where a = 1") time.Sleep(time.Millisecond) snapshotTime = time.Now() time.Sleep(time.Millisecond) tk.MustExec("alter table history_read add column b int") tk.MustExec("insert history_read values (8, 8), (9, 9)") tk.MustQuery("select * from history_read order by a").Check(testkit.Rows("2 <nil>", "4 <nil>", "8 8", "9 9")) tk.MustExec("set @@tidb_snapshot = '" + snapshotTime.Format("2006-01-02 15:04:05.999999") + "'") tk.MustQuery("select * from history_read order by a").Check(testkit.Rows("2", "4")) tk.MustExec("set @@tidb_snapshot = ''") tk.MustQuery("select * from history_read order by a").Check(testkit.Rows("2 <nil>", "4 <nil>", "8 8", "9 9")) }