diff --git a/executor/executor_test.go b/executor/executor_test.go index a078c8c68e517..28b2606efd31b 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -8850,6 +8850,14 @@ func (s *testStaleTxnSuite) TestInvalidReadTemporaryTable(c *C) { tk.MustExec("create global temporary table tmp1 " + "(id int not null primary key, code int not null, value int default null, unique key code(code))" + "on commit delete rows") + tk.MustExec("set @@tidb_enable_noop_functions=1;") + tk.MustExec("use test") + tk.MustExec("drop table if exists tmp2") + tk.MustExec("create temporary table tmp2 (id int not null primary key, code int not null, value int default null, unique key code(code));") + tk.MustExec("create table tmp3 (id int not null primary key, code int not null, value int default null, unique key code(code));") + tk.MustExec("create table tmp4 (id int not null primary key, code int not null, value int default null, unique key code(code));") + tk.MustExec("create temporary table tmp5(id int);") + tk.MustExec("create table tmp6 (id int primary key);") // sleep 1us to make test stale time.Sleep(time.Microsecond) @@ -8890,7 +8898,14 @@ func (s *testStaleTxnSuite) TestInvalidReadTemporaryTable(c *C) { } return sql[0:idx] + " as of timestamp NOW(6)" + sql[idx:] } + genLocalTemporarySQL := func(sql string) string { + return strings.Replace(sql, "tmp1", "tmp2", -1) + } + for _, query := range queries { + localSQL := genLocalTemporarySQL(query.sql) + queries = append(queries, struct{ sql string }{sql: localSQL}) + } for _, query := range queries { sql := addStaleReadToSQL(query.sql) if sql != "" { @@ -8908,6 +8923,16 @@ func (s *testStaleTxnSuite) TestInvalidReadTemporaryTable(c *C) { tk.MustExec(query.sql) } + // Test normal table when local temporary exits. + tk.MustExec("insert into tmp6 values(1);") + tk.MustExec("set @a=now(6);") + time.Sleep(time.Microsecond) + tk.MustExec("drop table tmp6") + tk.MustExec("create table tmp6 (id int primary key);") + tk.MustQuery("select * from tmp6 as of timestamp(@a) where id=1;").Check(testkit.Rows("1")) + tk.MustQuery("select * from tmp4 as of timestamp(@a), tmp3 as of timestamp(@a) where tmp3.id=1;") + tk.MustGetErrMsg("select * from tmp4 as of timestamp(@a), tmp2 as of timestamp(@a) where tmp2.id=1;", "can not stale read temporary table") + tk.MustExec("set transaction read only as of timestamp NOW(6)") tk.MustExec("start transaction") for _, query := range queries { diff --git a/planner/core/preprocess.go b/planner/core/preprocess.go index ec4eb6103da8d..90b3bd1c9c233 100644 --- a/planner/core/preprocess.go +++ b/planner/core/preprocess.go @@ -1585,10 +1585,27 @@ func (p *preprocessor) handleAsOfAndReadTS(node *ast.AsOfClause) { } if p.LastSnapshotTS != 0 { dom := domain.GetDomain(p.ctx) - p.InfoSchema, p.err = dom.GetSnapshotInfoSchema(p.LastSnapshotTS) - if p.err != nil { + is, err := dom.GetSnapshotInfoSchema(p.LastSnapshotTS) + // if infoschema is empty, LastSnapshotTS init failed + if err != nil { + p.err = err + return + } + if is == nil { + p.err = fmt.Errorf("can not get any information schema based on snapshotTS: %d", p.LastSnapshotTS) return } + // the same as session.wrapWithTemporaryTable + if _, ok := is.(*infoschema.TemporaryTableAttachedInfoSchema); !ok { + localTmp := p.ctx.GetSessionVars().LocalTemporaryTables + if localTmp != nil { + is = &infoschema.TemporaryTableAttachedInfoSchema{ + InfoSchema: is, + LocalTemporaryTables: localTmp.(*infoschema.LocalTemporaryTables), + } + } + } + p.InfoSchema = is } if p.flag&inPrepare == 0 { p.ctx.GetSessionVars().StmtCtx.IsStaleness = p.IsStaleness