From f451fb7f16cc88f2c0205f22f59425c98cacb420 Mon Sep 17 00:00:00 2001 From: sylzd Date: Tue, 17 Aug 2021 09:58:56 +0800 Subject: [PATCH 1/6] forbid stale read --- executor/executor_test.go | 26 ++++++++++++++++++++++++++ planner/core/preprocess.go | 16 ++++++++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/executor/executor_test.go b/executor/executor_test.go index e0cdefb03693a..b847ad41ea40f 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -8849,6 +8849,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) @@ -8889,7 +8897,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 != "" { @@ -8907,6 +8922,17 @@ 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 2efc7dedf5f3d..f2d0310cfc921 100644 --- a/planner/core/preprocess.go +++ b/planner/core/preprocess.go @@ -1593,10 +1593,22 @@ 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 err != nil { + p.err = err 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 From cdeb0a28e2344a3c53a8a1642e0960f4464cc5ba Mon Sep 17 00:00:00 2001 From: sylzd Date: Tue, 17 Aug 2021 10:04:49 +0800 Subject: [PATCH 2/6] fix --- planner/core/preprocess.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/planner/core/preprocess.go b/planner/core/preprocess.go index f2d0310cfc921..cbd858d872b45 100644 --- a/planner/core/preprocess.go +++ b/planner/core/preprocess.go @@ -1594,7 +1594,8 @@ func (p *preprocessor) handleAsOfAndReadTS(node *ast.AsOfClause) { if p.LastSnapshotTS != 0 { dom := domain.GetDomain(p.ctx) is, err := dom.GetSnapshotInfoSchema(p.LastSnapshotTS) - if err != nil { + // if infoschema is empty, LastSnapshotTS init failed + if err != nil || is == nil{ p.err = err return } From 37ac351a38af55dd0549266c0fc15add330ee634 Mon Sep 17 00:00:00 2001 From: sylzd Date: Tue, 17 Aug 2021 10:17:04 +0800 Subject: [PATCH 3/6] fix check --- executor/executor_test.go | 1 - planner/core/preprocess.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/executor/executor_test.go b/executor/executor_test.go index b847ad41ea40f..dabd517b1e10a 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -8932,7 +8932,6 @@ func (s *testStaleTxnSuite) TestInvalidReadTemporaryTable(c *C) { 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 cbd858d872b45..a1a139e3f1c5b 100644 --- a/planner/core/preprocess.go +++ b/planner/core/preprocess.go @@ -1595,7 +1595,7 @@ func (p *preprocessor) handleAsOfAndReadTS(node *ast.AsOfClause) { dom := domain.GetDomain(p.ctx) is, err := dom.GetSnapshotInfoSchema(p.LastSnapshotTS) // if infoschema is empty, LastSnapshotTS init failed - if err != nil || is == nil{ + if err != nil || is == nil { p.err = err return } From 3eaaac9cc8b306b7c0474d0e9b14d72f5b204653 Mon Sep 17 00:00:00 2001 From: sylzd Date: Tue, 17 Aug 2021 19:22:20 +0800 Subject: [PATCH 4/6] add error info of empty info schema --- planner/core/preprocess.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/planner/core/preprocess.go b/planner/core/preprocess.go index defa3aa33e034..03590dc221364 100644 --- a/planner/core/preprocess.go +++ b/planner/core/preprocess.go @@ -1596,10 +1596,14 @@ func (p *preprocessor) handleAsOfAndReadTS(node *ast.AsOfClause) { dom := domain.GetDomain(p.ctx) is, err := dom.GetSnapshotInfoSchema(p.LastSnapshotTS) // if infoschema is empty, LastSnapshotTS init failed - if err != nil || is == nil { + if err != nil { p.err = err return } + if is == nil { + p.err = errors.New("Get empty information schema based on snapshotTS") + return + } // the same as session.wrapWithTemporaryTable if _, ok := is.(*infoschema.TemporaryTableAttachedInfoSchema); !ok { localTmp := p.ctx.GetSessionVars().LocalTemporaryTables From 75ef9256eb508f4c2a04400f0e5dd89c16924c10 Mon Sep 17 00:00:00 2001 From: sylzd Date: Tue, 17 Aug 2021 19:22:57 +0800 Subject: [PATCH 5/6] add error info of empty info schema --- planner/core/preprocess.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/planner/core/preprocess.go b/planner/core/preprocess.go index 03590dc221364..de33c402cdae1 100644 --- a/planner/core/preprocess.go +++ b/planner/core/preprocess.go @@ -1601,7 +1601,7 @@ func (p *preprocessor) handleAsOfAndReadTS(node *ast.AsOfClause) { return } if is == nil { - p.err = errors.New("Get empty information schema based on snapshotTS") + p.err = errors.New("can not get any information schema based on snapshotTS") return } // the same as session.wrapWithTemporaryTable From 8f15def1c9cfbd14a88ae8139365d4ee914d3d98 Mon Sep 17 00:00:00 2001 From: sylzd Date: Tue, 17 Aug 2021 19:27:46 +0800 Subject: [PATCH 6/6] fix error info --- planner/core/preprocess.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/planner/core/preprocess.go b/planner/core/preprocess.go index de33c402cdae1..32e629d6e6b4a 100644 --- a/planner/core/preprocess.go +++ b/planner/core/preprocess.go @@ -1601,7 +1601,7 @@ func (p *preprocessor) handleAsOfAndReadTS(node *ast.AsOfClause) { return } if is == nil { - p.err = errors.New("can not get any information schema based on snapshotTS") + p.err = fmt.Errorf("can not get any information schema based on snapshotTS: %d", p.LastSnapshotTS) return } // the same as session.wrapWithTemporaryTable