From 36bf288c15aa6d47ea9b14a63d4b4e2e78f968b4 Mon Sep 17 00:00:00 2001 From: Reminiscent Date: Wed, 27 Jul 2022 16:38:43 +0800 Subject: [PATCH 01/11] planner: skip the optimizer for the execute statement --- executor/compiler.go | 24 +++++++++++++++++++++--- planner/optimize.go | 19 +++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/executor/compiler.go b/executor/compiler.go index 894e86e6b7ba8..63ac8af8e2d1d 100644 --- a/executor/compiler.go +++ b/executor/compiler.go @@ -28,6 +28,8 @@ import ( "github.com/pingcap/tidb/sessionctx" "github.com/pingcap/tidb/sessiontxn" "github.com/pingcap/tidb/sessiontxn/staleread" + "github.com/pingcap/tidb/types" + "github.com/pingcap/tidb/util/logutil" ) var ( @@ -77,9 +79,25 @@ func (c *Compiler) Compile(ctx context.Context, stmtNode ast.StmtNode) (*ExecStm }) is := sessiontxn.GetTxnManager(c.Ctx).GetTxnInfoSchema() - finalPlan, names, err := planner.Optimize(ctx, c.Ctx, stmtNode, is) - if err != nil { - return nil, err + var ( + finalPlan plannercore.Plan + names types.NameSlice + execAST *ast.ExecuteStmt + ok bool + ) + if execAST, ok = stmtNode.(*ast.ExecuteStmt); ok { + finalPlan, names, err = planner.OptimizeExecStmt(ctx, c.Ctx, execAST, is) + if err != nil { + // Record the error and use the general path + ok = false + logutil.Logger(ctx).Info("Execute statement ...") + } + } + if !ok { + finalPlan, names, err = planner.Optimize(ctx, c.Ctx, stmtNode, is) + if err != nil { + return nil, err + } } failpoint.Inject("assertStmtCtxIsStaleness", func(val failpoint.Value) { diff --git a/planner/optimize.go b/planner/optimize.go index 16971fb00b638..ceb86e445067d 100644 --- a/planner/optimize.go +++ b/planner/optimize.go @@ -372,6 +372,25 @@ func optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is in return finalPlan, names, cost, err } +// OptimizeExecStmt to handle the "execute" statement +func OptimizeExecStmt(ctx context.Context, sctx sessionctx.Context, + execAst *ast.ExecuteStmt, is infoschema.InfoSchema) (plannercore.Plan, types.NameSlice, error) { + builder := planBuilderPool.Get().(*plannercore.PlanBuilder) + defer planBuilderPool.Put(builder.ResetForReuse()) + + builder.Init(sctx, is, nil) + p, err := builder.Build(ctx, execAst) + if err != nil { + return nil, nil, err + } + if execPlan, ok := p.(*plannercore.Execute); ok { + err = execPlan.OptimizePreparedPlan(ctx, sctx, is) + return execPlan.Plan, execPlan.OutputNames(), err + } + err = errors.Errorf("invalid result plan type, should be Execute") + return nil, nil, err +} + // ExtractSelectAndNormalizeDigest extract the select statement and normalize it. func ExtractSelectAndNormalizeDigest(stmtNode ast.StmtNode, specifiledDB string) (ast.StmtNode, string, string, error) { switch x := stmtNode.(type) { From 547d9cafe094baca253f06102e9790d66bf9d2e8 Mon Sep 17 00:00:00 2001 From: Reminiscent Date: Wed, 27 Jul 2022 16:44:21 +0800 Subject: [PATCH 02/11] refactor the code --- executor/compiler.go | 12 +++--------- executor/prepared.go | 2 +- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/executor/compiler.go b/executor/compiler.go index 63ac8af8e2d1d..b243c2743a075 100644 --- a/executor/compiler.go +++ b/executor/compiler.go @@ -29,7 +29,6 @@ import ( "github.com/pingcap/tidb/sessiontxn" "github.com/pingcap/tidb/sessiontxn/staleread" "github.com/pingcap/tidb/types" - "github.com/pingcap/tidb/util/logutil" ) var ( @@ -82,18 +81,13 @@ func (c *Compiler) Compile(ctx context.Context, stmtNode ast.StmtNode) (*ExecStm var ( finalPlan plannercore.Plan names types.NameSlice - execAST *ast.ExecuteStmt - ok bool ) - if execAST, ok = stmtNode.(*ast.ExecuteStmt); ok { + if execAST, ok := stmtNode.(*ast.ExecuteStmt); ok { finalPlan, names, err = planner.OptimizeExecStmt(ctx, c.Ctx, execAST, is) if err != nil { - // Record the error and use the general path - ok = false - logutil.Logger(ctx).Info("Execute statement ...") + return nil, err } - } - if !ok { + } else { finalPlan, names, err = planner.Optimize(ctx, c.Ctx, stmtNode, is) if err != nil { return nil, err diff --git a/executor/prepared.go b/executor/prepared.go index 26aeecc7d107b..7c95a368ff5b7 100644 --- a/executor/prepared.go +++ b/executor/prepared.go @@ -322,7 +322,7 @@ func CompileExecutePreparedStmt(ctx context.Context, sctx sessionctx.Context, defer func() { sctx.GetSessionVars().DurationCompile = time.Since(startTime) }() - execPlan, names, err := planner.Optimize(ctx, sctx, execStmt, is) + execPlan, names, err := planner.OptimizeExecStmt(ctx, sctx, execStmt, is) if err != nil { return nil, err } From f97dba59b3bd2d7d3d0311a73d7f83ec79f80537 Mon Sep 17 00:00:00 2001 From: Reminiscent Date: Thu, 28 Jul 2022 15:43:44 +0800 Subject: [PATCH 03/11] fix ut --- planner/optimize.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/planner/optimize.go b/planner/optimize.go index ceb86e445067d..fd28dfdcf9b17 100644 --- a/planner/optimize.go +++ b/planner/optimize.go @@ -385,7 +385,7 @@ func OptimizeExecStmt(ctx context.Context, sctx sessionctx.Context, } if execPlan, ok := p.(*plannercore.Execute); ok { err = execPlan.OptimizePreparedPlan(ctx, sctx, is) - return execPlan.Plan, execPlan.OutputNames(), err + return execPlan, execPlan.OutputNames(), err } err = errors.Errorf("invalid result plan type, should be Execute") return nil, nil, err From 48d416d2eab9e2d842e5aefcd0d527e0fa0f7e56 Mon Sep 17 00:00:00 2001 From: Reminiscent Date: Thu, 28 Jul 2022 18:22:15 +0800 Subject: [PATCH 04/11] fixut --- planner/optimize.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/planner/optimize.go b/planner/optimize.go index fd28dfdcf9b17..e6aa2a997b7d4 100644 --- a/planner/optimize.go +++ b/planner/optimize.go @@ -384,6 +384,26 @@ func OptimizeExecStmt(ctx context.Context, sctx sessionctx.Context, return nil, nil, err } if execPlan, ok := p.(*plannercore.Execute); ok { + sessVars := sctx.GetSessionVars() + + if !sctx.GetSessionVars().InRestrictedSQL && variable.RestrictedReadOnly.Load() || variable.VarTiDBSuperReadOnly.Load() { + allowed, err := allowInReadOnlyMode(sctx, execAst) + if err != nil { + return nil, nil, err + } + if !allowed { + return nil, nil, errors.Trace(core.ErrSQLInReadOnlyMode) + } + } + + // Because for write stmt, TiFlash has a different results when lock the data in point get plan. We ban the TiFlash + // engine in not read only stmt. + if _, isolationReadContainTiFlash := sessVars.IsolationReadEngines[kv.TiFlash]; isolationReadContainTiFlash && !IsReadOnly(execAst, sessVars) { + delete(sessVars.IsolationReadEngines, kv.TiFlash) + defer func() { + sessVars.IsolationReadEngines[kv.TiFlash] = struct{}{} + }() + } err = execPlan.OptimizePreparedPlan(ctx, sctx, is) return execPlan, execPlan.OutputNames(), err } From 975147988c0b038d8eac8cc7f1de5ea4803fa1bc Mon Sep 17 00:00:00 2001 From: Reminiscent Date: Wed, 3 Aug 2022 17:10:06 +0800 Subject: [PATCH 05/11] address comments --- planner/core/plan_cache.go | 7 +++++ planner/optimize.go | 64 ++++++++++++++++---------------------- 2 files changed, 34 insertions(+), 37 deletions(-) diff --git a/planner/core/plan_cache.go b/planner/core/plan_cache.go index 6aa57399bb601..fdf613cb035c6 100644 --- a/planner/core/plan_cache.go +++ b/planner/core/plan_cache.go @@ -29,6 +29,7 @@ import ( "github.com/pingcap/tidb/sessionctx" "github.com/pingcap/tidb/sessionctx/stmtctx" "github.com/pingcap/tidb/sessionctx/variable" + "github.com/pingcap/tidb/sessiontxn" "github.com/pingcap/tidb/table/tables" "github.com/pingcap/tidb/types" "github.com/pingcap/tidb/util/chunk" @@ -58,6 +59,12 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context, i var latestSchemaVersion int64 if prepared.UseCache { + txnManger := sessiontxn.GetTxnManager(sctx) + if err = txnManger.AdviseWarmup(); err != nil { + return nil, nil, err + } + + // generate the plan cache key bindSQL, ignorePlanCache = GetBindSQL4PlanCache(sctx, preparedStmt) if sctx.GetSessionVars().IsIsolation(ast.ReadCommitted) || preparedStmt.ForUpdateRead { // In Rc or ForUpdateRead, we should check if the information schema has been changed since diff --git a/planner/optimize.go b/planner/optimize.go index e6aa2a997b7d4..fd44db6acd18e 100644 --- a/planner/optimize.go +++ b/planner/optimize.go @@ -306,31 +306,17 @@ func optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is in }) // build logical plan - sctx.GetSessionVars().PlanID = 0 - sctx.GetSessionVars().PlanColumnID = 0 - sctx.GetSessionVars().MapHashCode2UniqueID4ExtendedCol = nil hintProcessor := &hint.BlockHintProcessor{Ctx: sctx} - node.Accept(hintProcessor) - - failpoint.Inject("mockRandomPlanID", func() { - sctx.GetSessionVars().PlanID = rand.Intn(1000) // nolint:gosec - }) builder := planBuilderPool.Get().(*plannercore.PlanBuilder) defer planBuilderPool.Put(builder.ResetForReuse()) - builder.Init(sctx, is, hintProcessor) - // reset fields about rewrite - sctx.GetSessionVars().RewritePhaseInfo.Reset() - beginRewrite := time.Now() - p, err := builder.Build(ctx, node) + p, err := buildLogicalPlan(ctx, sctx, node, hintProcessor, builder) if err != nil { return nil, nil, 0, err } - sctx.GetSessionVars().RewritePhaseInfo.DurationRewrite = time.Since(beginRewrite) - sctx.GetSessionVars().StmtCtx.Tables = builder.GetDBTableInfo() activeRoles := sctx.GetSessionVars().ActiveRoles // Check privilege. Maybe it's better to move this to the Preprocess, but // we need the table information to check privilege, which is collected @@ -377,33 +363,13 @@ func OptimizeExecStmt(ctx context.Context, sctx sessionctx.Context, execAst *ast.ExecuteStmt, is infoschema.InfoSchema) (plannercore.Plan, types.NameSlice, error) { builder := planBuilderPool.Get().(*plannercore.PlanBuilder) defer planBuilderPool.Put(builder.ResetForReuse()) - builder.Init(sctx, is, nil) - p, err := builder.Build(ctx, execAst) + + p, err := buildLogicalPlan(ctx, sctx, execAst, nil, builder) if err != nil { return nil, nil, err } if execPlan, ok := p.(*plannercore.Execute); ok { - sessVars := sctx.GetSessionVars() - - if !sctx.GetSessionVars().InRestrictedSQL && variable.RestrictedReadOnly.Load() || variable.VarTiDBSuperReadOnly.Load() { - allowed, err := allowInReadOnlyMode(sctx, execAst) - if err != nil { - return nil, nil, err - } - if !allowed { - return nil, nil, errors.Trace(core.ErrSQLInReadOnlyMode) - } - } - - // Because for write stmt, TiFlash has a different results when lock the data in point get plan. We ban the TiFlash - // engine in not read only stmt. - if _, isolationReadContainTiFlash := sessVars.IsolationReadEngines[kv.TiFlash]; isolationReadContainTiFlash && !IsReadOnly(execAst, sessVars) { - delete(sessVars.IsolationReadEngines, kv.TiFlash) - defer func() { - sessVars.IsolationReadEngines[kv.TiFlash] = struct{}{} - }() - } err = execPlan.OptimizePreparedPlan(ctx, sctx, is) return execPlan, execPlan.OutputNames(), err } @@ -411,6 +377,30 @@ func OptimizeExecStmt(ctx context.Context, sctx sessionctx.Context, return nil, nil, err } +func buildLogicalPlan(ctx context.Context, sctx sessionctx.Context, node ast.Node, hintProcessor *hint.BlockHintProcessor, builder *plannercore.PlanBuilder) (plannercore.Plan, error) { + sctx.GetSessionVars().PlanID = 0 + sctx.GetSessionVars().PlanColumnID = 0 + sctx.GetSessionVars().MapHashCode2UniqueID4ExtendedCol = nil + if hintProcessor != nil { + node.Accept(hintProcessor) + } + + failpoint.Inject("mockRandomPlanID", func() { + sctx.GetSessionVars().PlanID = rand.Intn(1000) // nolint:gosec + }) + + // reset fields about rewrite + sctx.GetSessionVars().RewritePhaseInfo.Reset() + beginRewrite := time.Now() + p, err := builder.Build(ctx, node) + if err != nil { + return nil, err + } + sctx.GetSessionVars().RewritePhaseInfo.DurationRewrite = time.Since(beginRewrite) + sctx.GetSessionVars().StmtCtx.Tables = builder.GetDBTableInfo() + return p, nil +} + // ExtractSelectAndNormalizeDigest extract the select statement and normalize it. func ExtractSelectAndNormalizeDigest(stmtNode ast.StmtNode, specifiledDB string) (ast.StmtNode, string, string, error) { switch x := stmtNode.(type) { From a40f78024773b1e2c517128a1d49dccf794106cf Mon Sep 17 00:00:00 2001 From: Reminiscent Date: Thu, 4 Aug 2022 16:13:39 +0800 Subject: [PATCH 06/11] fix ut --- planner/optimize.go | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/planner/optimize.go b/planner/optimize.go index ffda530716016..33eb1e4c7a367 100644 --- a/planner/optimize.go +++ b/planner/optimize.go @@ -359,8 +359,8 @@ func optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is in // OptimizeExecStmt to handle the "execute" statement func OptimizeExecStmt(ctx context.Context, sctx sessionctx.Context, - execAst *ast.ExecuteStmt, is infoschema.InfoSchema) (plannercore.Plan, types.NameSlice, error) { - builder := planBuilderPool.Get().(*plannercore.PlanBuilder) + execAst *ast.ExecuteStmt, is infoschema.InfoSchema) (core.Plan, types.NameSlice, error) { + builder := planBuilderPool.Get().(*core.PlanBuilder) defer planBuilderPool.Put(builder.ResetForReuse()) builder.Init(sctx, is, nil) @@ -368,7 +368,18 @@ func OptimizeExecStmt(ctx context.Context, sctx sessionctx.Context, if err != nil { return nil, nil, err } - if execPlan, ok := p.(*plannercore.Execute); ok { + if execPlan, ok := p.(*core.Execute); ok { + // Because for write stmt, TiFlash has a different results when lock the data in point get plan. We ban the TiFlash + // engine in not read only stmt. + // TODO: this part will be removed later + sessVars := sctx.GetSessionVars() + if _, isolationReadContainTiFlash := sessVars.IsolationReadEngines[kv.TiFlash]; isolationReadContainTiFlash && !IsReadOnly(execAst, sessVars) { + delete(sessVars.IsolationReadEngines, kv.TiFlash) + defer func() { + sessVars.IsolationReadEngines[kv.TiFlash] = struct{}{} + }() + } + err = execPlan.OptimizePreparedPlan(ctx, sctx, is) return execPlan, execPlan.OutputNames(), err } @@ -376,7 +387,7 @@ func OptimizeExecStmt(ctx context.Context, sctx sessionctx.Context, return nil, nil, err } -func buildLogicalPlan(ctx context.Context, sctx sessionctx.Context, node ast.Node, hintProcessor *hint.BlockHintProcessor, builder *plannercore.PlanBuilder) (plannercore.Plan, error) { +func buildLogicalPlan(ctx context.Context, sctx sessionctx.Context, node ast.Node, hintProcessor *hint.BlockHintProcessor, builder *core.PlanBuilder) (core.Plan, error) { sctx.GetSessionVars().PlanID = 0 sctx.GetSessionVars().PlanColumnID = 0 sctx.GetSessionVars().MapHashCode2UniqueID4ExtendedCol = nil From ece4f7d0f2f47a679e07e34a8ef56ce2d86393a6 Mon Sep 17 00:00:00 2001 From: Reminiscent Date: Fri, 5 Aug 2022 16:07:55 +0800 Subject: [PATCH 07/11] fix ut --- planner/core/plan_cache.go | 17 +++++------------ planner/optimize.go | 13 ++++--------- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/planner/core/plan_cache.go b/planner/core/plan_cache.go index a3cdadb3c5788..459aa6f65c83d 100644 --- a/planner/core/plan_cache.go +++ b/planner/core/plan_cache.go @@ -30,7 +30,6 @@ import ( "github.com/pingcap/tidb/sessionctx" "github.com/pingcap/tidb/sessionctx/stmtctx" "github.com/pingcap/tidb/sessionctx/variable" - "github.com/pingcap/tidb/sessiontxn" "github.com/pingcap/tidb/table/tables" "github.com/pingcap/tidb/types" "github.com/pingcap/tidb/util/chunk" @@ -59,13 +58,13 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context, i // rebuild the plan. So we set this value in rc or for update read. In other cases, let it be 0. var latestSchemaVersion int64 - if prepared.UseCache { - txnManger := sessiontxn.GetTxnManager(sctx) - if err = txnManger.AdviseWarmup(); err != nil { - return nil, nil, err + if prepared.UseCache && prepared.CachedPlan != nil && !ignorePlanCache { // for point query plan + if plan, names, ok, err := getPointQueryPlan(prepared, sessVars, stmtCtx); ok { + return plan, names, err } + } - // generate the plan cache key + if prepared.UseCache { bindSQL, ignorePlanCache = GetBindSQL4PlanCache(sctx, preparedStmt) if sctx.GetSessionVars().IsIsolation(ast.ReadCommitted) || preparedStmt.ForUpdateRead { // In Rc or ForUpdateRead, we should check if the information schema has been changed since @@ -82,12 +81,6 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context, i isBinProtocol := len(binProtoVars) > 0 varsNum, binVarTypes, txtVarTypes := parseParamTypes(sctx, isBinProtocol, binProtoVars, txtProtoVars) - if prepared.UseCache && prepared.CachedPlan != nil && !ignorePlanCache { // for point query plan - if plan, names, ok, err := getPointQueryPlan(prepared, sessVars, stmtCtx); ok { - return plan, names, err - } - } - if prepared.UseCache && !ignorePlanCache { // for general plans if plan, names, ok, err := getGeneralPlan(ctx, sctx, cacheKey, bindSQL, is, preparedStmt, binVarTypes, txtVarTypes); err != nil || ok { diff --git a/planner/optimize.go b/planner/optimize.go index 33eb1e4c7a367..dd0c875374b91 100644 --- a/planner/optimize.go +++ b/planner/optimize.go @@ -306,12 +306,11 @@ func optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is in // build logical plan hintProcessor := &hint.BlockHintProcessor{Ctx: sctx} - + node.Accept(hintProcessor) builder := planBuilderPool.Get().(*core.PlanBuilder) defer planBuilderPool.Put(builder.ResetForReuse()) builder.Init(sctx, is, hintProcessor) - - p, err := buildLogicalPlan(ctx, sctx, node, hintProcessor, builder) + p, err := buildLogicalPlan(ctx, sctx, node, builder) if err != nil { return nil, nil, 0, err } @@ -364,14 +363,13 @@ func OptimizeExecStmt(ctx context.Context, sctx sessionctx.Context, defer planBuilderPool.Put(builder.ResetForReuse()) builder.Init(sctx, is, nil) - p, err := buildLogicalPlan(ctx, sctx, execAst, nil, builder) + p, err := buildLogicalPlan(ctx, sctx, execAst, builder) if err != nil { return nil, nil, err } if execPlan, ok := p.(*core.Execute); ok { // Because for write stmt, TiFlash has a different results when lock the data in point get plan. We ban the TiFlash // engine in not read only stmt. - // TODO: this part will be removed later sessVars := sctx.GetSessionVars() if _, isolationReadContainTiFlash := sessVars.IsolationReadEngines[kv.TiFlash]; isolationReadContainTiFlash && !IsReadOnly(execAst, sessVars) { delete(sessVars.IsolationReadEngines, kv.TiFlash) @@ -387,13 +385,10 @@ func OptimizeExecStmt(ctx context.Context, sctx sessionctx.Context, return nil, nil, err } -func buildLogicalPlan(ctx context.Context, sctx sessionctx.Context, node ast.Node, hintProcessor *hint.BlockHintProcessor, builder *core.PlanBuilder) (core.Plan, error) { +func buildLogicalPlan(ctx context.Context, sctx sessionctx.Context, node ast.Node, builder *core.PlanBuilder) (core.Plan, error) { sctx.GetSessionVars().PlanID = 0 sctx.GetSessionVars().PlanColumnID = 0 sctx.GetSessionVars().MapHashCode2UniqueID4ExtendedCol = nil - if hintProcessor != nil { - node.Accept(hintProcessor) - } failpoint.Inject("mockRandomPlanID", func() { sctx.GetSessionVars().PlanID = rand.Intn(1000) // nolint:gosec From 03a537de424e4adc3aec137fd2fda6de7dd8508c Mon Sep 17 00:00:00 2001 From: Reminiscent Date: Fri, 5 Aug 2022 16:46:53 +0800 Subject: [PATCH 08/11] address comments --- planner/optimize.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/planner/optimize.go b/planner/optimize.go index dd0c875374b91..daf43c1dd3a4a 100644 --- a/planner/optimize.go +++ b/planner/optimize.go @@ -330,12 +330,6 @@ func optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is in return nil, nil, 0, err } - // Handle the execute statement. - if execPlan, ok := p.(*core.Execute); ok { - err := execPlan.OptimizePreparedPlan(ctx, sctx, is) - return p, p.OutputNames(), 0, err - } - names := p.OutputNames() // Handle the non-logical plan statement. From ecdeb4aa06d7cdbf6e749a0dd7e574942fee02f5 Mon Sep 17 00:00:00 2001 From: Reminiscent Date: Fri, 5 Aug 2022 17:13:35 +0800 Subject: [PATCH 09/11] address comments --- executor/compiler.go | 18 +++--------------- planner/optimize.go | 16 ++++++---------- 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/executor/compiler.go b/executor/compiler.go index b243c2743a075..894e86e6b7ba8 100644 --- a/executor/compiler.go +++ b/executor/compiler.go @@ -28,7 +28,6 @@ import ( "github.com/pingcap/tidb/sessionctx" "github.com/pingcap/tidb/sessiontxn" "github.com/pingcap/tidb/sessiontxn/staleread" - "github.com/pingcap/tidb/types" ) var ( @@ -78,20 +77,9 @@ func (c *Compiler) Compile(ctx context.Context, stmtNode ast.StmtNode) (*ExecStm }) is := sessiontxn.GetTxnManager(c.Ctx).GetTxnInfoSchema() - var ( - finalPlan plannercore.Plan - names types.NameSlice - ) - if execAST, ok := stmtNode.(*ast.ExecuteStmt); ok { - finalPlan, names, err = planner.OptimizeExecStmt(ctx, c.Ctx, execAST, is) - if err != nil { - return nil, err - } - } else { - finalPlan, names, err = planner.Optimize(ctx, c.Ctx, stmtNode, is) - if err != nil { - return nil, err - } + finalPlan, names, err := planner.Optimize(ctx, c.Ctx, stmtNode, is) + if err != nil { + return nil, err } failpoint.Inject("assertStmtCtxIsStaleness", func(val failpoint.Value) { diff --git a/planner/optimize.go b/planner/optimize.go index daf43c1dd3a4a..df41dca0efbf7 100644 --- a/planner/optimize.go +++ b/planner/optimize.go @@ -97,6 +97,12 @@ func Optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is in }() } + // handle the execute statement + if execAST, ok := node.(*ast.ExecuteStmt); ok { + p, names, err := OptimizeExecStmt(ctx, sctx, execAST, is) + return p, names, err + } + tableHints := hint.ExtractTableHintsFromStmtNode(node, sctx) originStmtHints, originStmtHintsOffs, warns := handleStmtHints(tableHints) sessVars.StmtCtx.StmtHints = originStmtHints @@ -362,16 +368,6 @@ func OptimizeExecStmt(ctx context.Context, sctx sessionctx.Context, return nil, nil, err } if execPlan, ok := p.(*core.Execute); ok { - // Because for write stmt, TiFlash has a different results when lock the data in point get plan. We ban the TiFlash - // engine in not read only stmt. - sessVars := sctx.GetSessionVars() - if _, isolationReadContainTiFlash := sessVars.IsolationReadEngines[kv.TiFlash]; isolationReadContainTiFlash && !IsReadOnly(execAst, sessVars) { - delete(sessVars.IsolationReadEngines, kv.TiFlash) - defer func() { - sessVars.IsolationReadEngines[kv.TiFlash] = struct{}{} - }() - } - err = execPlan.OptimizePreparedPlan(ctx, sctx, is) return execPlan, execPlan.OutputNames(), err } From 73dcf1288da4f31e2ebb986f71fc2dbe3449dd4f Mon Sep 17 00:00:00 2001 From: Reminiscent Date: Fri, 5 Aug 2022 17:15:02 +0800 Subject: [PATCH 10/11] address comments --- executor/prepared.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/executor/prepared.go b/executor/prepared.go index b208b22ba8d71..64d2dd1cf321b 100644 --- a/executor/prepared.go +++ b/executor/prepared.go @@ -324,7 +324,7 @@ func CompileExecutePreparedStmt(ctx context.Context, sctx sessionctx.Context, defer func() { sctx.GetSessionVars().DurationCompile = time.Since(startTime) }() - execPlan, names, err := planner.OptimizeExecStmt(ctx, sctx, execStmt, is) + execPlan, names, err := planner.Optimize(ctx, sctx, execStmt, is) if err != nil { return nil, err } From 078898806e2fb986298a67f38266ebdb5bc2f699 Mon Sep 17 00:00:00 2001 From: Reminiscent Date: Mon, 8 Aug 2022 11:45:02 +0800 Subject: [PATCH 11/11] address comments --- planner/core/plan_cache.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/planner/core/plan_cache.go b/planner/core/plan_cache.go index b60cc7b0cf210..9a4e6b67a564d 100644 --- a/planner/core/plan_cache.go +++ b/planner/core/plan_cache.go @@ -58,12 +58,6 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context, i // rebuild the plan. So we set this value in rc or for update read. In other cases, let it be 0. var latestSchemaVersion int64 - if prepared.UseCache && prepared.CachedPlan != nil && !ignorePlanCache { // for point query plan - if plan, names, ok, err := getPointQueryPlan(prepared, sessVars, stmtCtx); ok { - return plan, names, err - } - } - if prepared.UseCache { bindSQL, ignorePlanCache = GetBindSQL4PlanCache(sctx, preparedStmt) if sctx.GetSessionVars().IsIsolation(ast.ReadCommitted) || preparedStmt.ForUpdateRead { @@ -80,6 +74,12 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context, i varsNum, txtVarTypes := parseParamTypes(sctx, txtProtoVars) + if prepared.UseCache && prepared.CachedPlan != nil && !ignorePlanCache { // for point query plan + if plan, names, ok, err := getPointQueryPlan(prepared, sessVars, stmtCtx); ok { + return plan, names, err + } + } + if prepared.UseCache && !ignorePlanCache { // for general plans if plan, names, ok, err := getGeneralPlan(ctx, sctx, cacheKey, bindSQL, is, preparedStmt, txtVarTypes); err != nil || ok {