diff --git a/planner/core/common_plans.go b/planner/core/common_plans.go index 45d37e63e2096..d955e8853471d 100644 --- a/planner/core/common_plans.go +++ b/planner/core/common_plans.go @@ -38,9 +38,11 @@ import ( "github.com/pingcap/tidb/util/chunk" "github.com/pingcap/tidb/util/hint" "github.com/pingcap/tidb/util/kvcache" + "github.com/pingcap/tidb/util/logutil" "github.com/pingcap/tidb/util/math" "github.com/pingcap/tidb/util/ranger" "github.com/pingcap/tidb/util/texttree" + "go.uber.org/zap" ) var planCacheCounter = metrics.PlanCacheCounter.WithLabelValues("prepare") @@ -273,6 +275,11 @@ func (e *Execute) setFoundInPlanCache(sctx sessionctx.Context, opt bool) error { func (e *Execute) getPhysicalPlan(ctx context.Context, sctx sessionctx.Context, is infoschema.InfoSchema, preparedStmt *CachedPrepareStmt) error { stmtCtx := sctx.GetSessionVars().StmtCtx prepared := preparedStmt.PreparedAst + stmtCtx.UseCache = prepared.UseCache + var cacheKey kvcache.Key + if prepared.UseCache { + cacheKey = NewPSTMTPlanCacheKey(sctx.GetSessionVars(), e.ExecID, prepared.SchemaVersion) + } if prepared.CachedPlan != nil { // Rewriting the expression in the select.where condition will convert its // type from "paramMarker" to "Constant".When Point Select queries are executed, @@ -282,7 +289,8 @@ func (e *Execute) getPhysicalPlan(ctx context.Context, sctx sessionctx.Context, names := prepared.CachedNames.(types.NameSlice) err := e.rebuildRange(plan) if err != nil { - return err + logutil.BgLogger().Debug("rebuild range failed", zap.Error(err)) + goto REBUILD } if metrics.ResettablePlanCacheCounterFortTest { metrics.PlanCacheCounter.WithLabelValues("prepare").Inc() @@ -298,10 +306,7 @@ func (e *Execute) getPhysicalPlan(ctx context.Context, sctx sessionctx.Context, stmtCtx.PointExec = true return nil } - var cacheKey kvcache.Key - stmtCtx.UseCache = prepared.UseCache if prepared.UseCache { - cacheKey = NewPSTMTPlanCacheKey(sctx.GetSessionVars(), e.ExecID, prepared.SchemaVersion) if cacheValue, exists := sctx.PreparedPlanCache().Get(cacheKey); exists { if err := e.checkPreparedPriv(ctx, sctx, preparedStmt, is); err != nil { return err @@ -318,7 +323,12 @@ func (e *Execute) getPhysicalPlan(ctx context.Context, sctx sessionctx.Context, } } if planValid { - err := e.setFoundInPlanCache(sctx, true) + err := e.rebuildRange(cachedVal.Plan) + if err != nil { + logutil.BgLogger().Debug("rebuild range failed", zap.Error(err)) + goto REBUILD + } + err = e.setFoundInPlanCache(sctx, true) if err != nil { return err } @@ -327,10 +337,6 @@ func (e *Execute) getPhysicalPlan(ctx context.Context, sctx sessionctx.Context, } else { planCacheCounter.Inc() } - err = e.rebuildRange(cachedVal.Plan) - if err != nil { - return err - } e.names = cachedVal.OutPutNames e.Plan = cachedVal.Plan stmtCtx.SetPlanDigest(preparedStmt.NormalizedPlan, preparedStmt.PlanDigest) @@ -338,6 +344,8 @@ func (e *Execute) getPhysicalPlan(ctx context.Context, sctx sessionctx.Context, } } } + +REBUILD: p, names, err := OptimizeAstNode(ctx, sctx, prepared.Stmt, is) if err != nil { return err diff --git a/planner/core/prepare_test.go b/planner/core/prepare_test.go index 79532ea2de819..4b6d5b3da49dd 100644 --- a/planner/core/prepare_test.go +++ b/planner/core/prepare_test.go @@ -718,6 +718,39 @@ func (s *testPlanSerialSuite) TestPlanCacheHitInfo(c *C) { tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0")) } +func (s *testPlanSerialSuite) TestPlanCacheUnsignedHandleOverflow(c *C) { + defer testleak.AfterTest(c)() + store, dom, err := newStoreWithBootstrap() + c.Assert(err, IsNil) + tk := testkit.NewTestKit(c, store) + orgEnable := core.PreparedPlanCacheEnabled() + defer func() { + dom.Close() + store.Close() + core.SetPreparedPlanCache(orgEnable) + }() + core.SetPreparedPlanCache(true) + + tk.Se, err = session.CreateSession4TestWithOpt(store, &session.Opt{ + PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64), + }) + c.Assert(err, IsNil) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t(a bigint unsigned primary key)") + tk.MustExec("insert into t values(18446744073709551615)") + tk.MustExec("prepare stmt from 'select a from t where a=?'") + tk.MustExec("set @p = 1") + tk.MustQuery("execute stmt using @p").Check(testkit.Rows()) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) + tk.MustQuery("execute stmt using @p").Check(testkit.Rows()) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + tk.MustExec("set @p = 18446744073709551615") + tk.MustQuery("execute stmt using @p").Check(testkit.Rows("18446744073709551615")) + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) +} + func (s *testPrepareSuite) TestPrepareForGroupByMultiItems(c *C) { defer testleak.AfterTest(c)() store, dom, err := newStoreWithBootstrap()