Skip to content

Commit 48145ba

Browse files
authored
planner: not use the latest schema when plan-cache is off (#30959) (#40046)
close #30940
1 parent 5a7a495 commit 48145ba

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

planner/optimize.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"time"
2323

2424
"github.com/pingcap/errors"
25+
"github.com/pingcap/failpoint"
2526
"github.com/pingcap/parser"
2627
"github.com/pingcap/parser/ast"
2728
"github.com/pingcap/tidb/bindinfo"
@@ -238,12 +239,16 @@ func optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is in
238239
sctx.GetSessionVars().RewritePhaseInfo.DurationRewrite = time.Since(beginRewrite)
239240

240241
if execPlan, ok := p.(*plannercore.Execute); ok {
242+
failpoint.Inject("optimizeExecuteStmt", nil)
241243
execID := execPlan.ExecID
242244
if execPlan.Name != "" {
243245
execID = sctx.GetSessionVars().PreparedStmtNameToID[execPlan.Name]
244246
}
245247
if preparedPointer, ok := sctx.GetSessionVars().PreparedStmts[execID]; ok {
246-
if preparedObj, ok := preparedPointer.(*core.CachedPrepareStmt); ok && preparedObj.ForUpdateRead {
248+
// When plan cache is enabled, and it's a for-update read, use the latest schema to detect plan expired.
249+
// Otherwise, do not update schema to avoid plan and execution use different schema versions.
250+
if preparedObj, ok := preparedPointer.(*core.CachedPrepareStmt); ok && preparedObj.ForUpdateRead &&
251+
preparedObj.PreparedAst.UseCache {
247252
is = domain.GetDomain(sctx).InfoSchema()
248253
}
249254
}

session/pessimistic_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2648,3 +2648,31 @@ func (s *testPessimisticSuite) TestChangeLockToPut(c *C) {
26482648

26492649
tk.MustExec("admin check table t1")
26502650
}
2651+
2652+
func (s *testPessimisticSuite) TestIssue30940(c *C) {
2653+
tk := testkit.NewTestKitWithInit(c, s.store)
2654+
tk2 := testkit.NewTestKitWithInit(c, s.store)
2655+
2656+
tk.MustExec("use test")
2657+
tk2.MustExec("use test")
2658+
tk.MustExec("drop table if exists t")
2659+
tk.MustExec("create table t(id int primary key, v int)")
2660+
tk.MustExec("insert into t values(1, 1)")
2661+
2662+
stmts := []string{
2663+
"update t set v = v + 1 where id = 1",
2664+
"delete from t where id = 1",
2665+
}
2666+
errCh := make(chan error, 1)
2667+
for _, stmt := range stmts {
2668+
tk.MustExec(fmt.Sprintf("prepare t from '%s'", stmt))
2669+
tk2.MustExec("alter table t add column a int")
2670+
c.Assert(failpoint.Enable("github.com/pingcap/tidb/planner/optimizeExecuteStmt", "pause"), IsNil)
2671+
go func() {
2672+
errCh <- tk.ExecToErr("execute t")
2673+
}()
2674+
tk2.MustExec("alter table t drop column a")
2675+
c.Assert(failpoint.Disable("github.com/pingcap/tidb/planner/optimizeExecuteStmt"), IsNil)
2676+
c.Assert(<-errCh, IsNil)
2677+
}
2678+
}

0 commit comments

Comments
 (0)