diff --git a/executor/seqtest/prepared_test.go b/executor/seqtest/prepared_test.go index b3627ec04b7f3..f63d8e5e57c81 100644 --- a/executor/seqtest/prepared_test.go +++ b/executor/seqtest/prepared_test.go @@ -15,14 +15,18 @@ package executor_test import ( "context" + "crypto/tls" "math" + "time" . "github.com/pingcap/check" + "github.com/pingcap/parser/mysql" "github.com/pingcap/tidb/executor" "github.com/pingcap/tidb/metrics" plannercore "github.com/pingcap/tidb/planner/core" "github.com/pingcap/tidb/session" "github.com/pingcap/tidb/types" + "github.com/pingcap/tidb/util" "github.com/pingcap/tidb/util/kvcache" "github.com/pingcap/tidb/util/testkit" dto "github.com/prometheus/client_model/go" @@ -725,3 +729,63 @@ func (s *seqTestSuite) TestPreparedIssue8644(c *C) { r.Check(testkit.Rows("a", "aaaaaaaaaaaaaaaaaa")) } } + +// mockSessionManager is a mocked session manager which is used for test. +type mockSessionManager1 struct { + Se session.Session +} + +// ShowProcessList implements the SessionManager.ShowProcessList interface. +func (msm *mockSessionManager1) ShowProcessList() map[uint64]*util.ProcessInfo { + ret := make(map[uint64]*util.ProcessInfo) + return ret +} + +func (msm *mockSessionManager1) GetProcessInfo(id uint64) (*util.ProcessInfo, bool) { + pi := msm.Se.ShowProcess() + return pi, true +} + +// Kill implements the SessionManager.Kill interface. +func (msm *mockSessionManager1) Kill(cid uint64, query bool) {} + +func (msm *mockSessionManager1) UpdateTLSConfig(cfg *tls.Config) {} + +func (s *seqTestSuite) TestPreparedIssue17419(c *C) { + ctx := context.Background() + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (a int)") + tk.MustExec("insert into t (a) values (1), (2), (3)") + + tk1 := testkit.NewTestKit(c, s.store) + + var err error + tk1.Se, err = session.CreateSession4Test(s.store) + c.Assert(err, IsNil) + tk1.GetConnectionID() + + query := "select * from test.t" + stmtID, _, _, err := tk1.Se.PrepareStmt(query) + c.Assert(err, IsNil) + + sm := &mockSessionManager1{ + Se: tk1.Se, + } + tk1.Se.SetSessionManager(sm) + s.domain.ExpensiveQueryHandle().SetSessionManager(sm) + + rs, err := tk1.Se.ExecutePreparedStmt(ctx, stmtID, []types.Datum{}) + c.Assert(err, IsNil) + tk1.ResultSetToResult(rs, Commentf("%v", rs)).Check(testkit.Rows("1", "2", "3")) + tk1.Se.SetProcessInfo("", time.Now(), mysql.ComStmtExecute, 0) + + s.domain.ExpensiveQueryHandle().LogOnQueryExceedMemQuota(tk.Se.GetSessionVars().ConnectionID) + + // After entirely fixing https://github.com/pingcap/tidb/issues/17419 + // c.Assert(tk1.Se.ShowProcess().Plan, NotNil) + // _, ok := tk1.Se.ShowProcess().Plan.(*plannercore.Execute) + // c.Assert(ok, IsTrue) +} diff --git a/planner/core/util.go b/planner/core/util.go index dcfc7c56b0428..84b77e779d2b8 100644 --- a/planner/core/util.go +++ b/planner/core/util.go @@ -217,6 +217,11 @@ func BuildPhysicalJoinSchema(joinType JoinType, join PhysicalPlan) *expression.S // GetStatsInfo gets the statistics info from a physical plan tree. func GetStatsInfo(i interface{}) map[string]uint64 { + if i == nil { + // it's a workaround for https://github.com/pingcap/tidb/issues/17419 + // To entirely fix this, uncomment the assertion in TestPreparedIssue17419 + return nil + } p := i.(Plan) var physicalPlan PhysicalPlan switch x := p.(type) {