diff --git a/infoschema/cluster_tables_test.go b/infoschema/cluster_tables_test.go index cbe4590f57a38..53339ffc209ab 100644 --- a/infoschema/cluster_tables_test.go +++ b/infoschema/cluster_tables_test.go @@ -1264,3 +1264,37 @@ func TestNewCreatedBindingCanWorkWithPlanCache(t *testing.T) { tk.MustExec("execute stmt using @a") tk.MustQuery("select @@last_plan_from_binding").Check(testkit.Rows("1")) } + +func TestCreateBindingForPrepareToken(t *testing.T) { + s := new(clusterTablesSuite) + s.store, s.dom = testkit.CreateMockStoreAndDomain(t) + s.rpcserver, s.listenAddr = s.setUpRPCService(t, "127.0.0.1:0", nil) + s.httpServer, s.mockAddr = s.setUpMockPDHTTPServer() + s.startTime = time.Now() + defer s.httpServer.Close() + defer s.rpcserver.Stop() + tk := s.newTestKitWithRoot(t) + require.NoError(t, tk.Session().Auth(&auth.UserIdentity{Username: "root", Hostname: "%"}, nil, nil)) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t(a int, b time, c varchar(5))") + + //some builtin functions listed in https://dev.mysql.com/doc/refman/8.0/en/function-resolution.html + cases := []string{ + "select std(a) from t", + "select cast(a as decimal(10, 2)) from t", + "select bit_or(a) from t", + "select min(a) from t", + "select max(a) from t", + "select substr(c, 1, 2) from t", + } + + for _, sql := range cases { + prep := fmt.Sprintf("prepare stmt from '%s'", sql) + tk.MustExec(prep) + tk.MustExec("execute stmt") + planDigest := tk.MustQuery(fmt.Sprintf("select plan_digest from information_schema.statements_summary where query_sample_text = '%s'", sql)).Rows() + tk.MustExec(fmt.Sprintf("create binding from history using plan digest '%s'", planDigest[0][0])) + } +} diff --git a/util/stmtsummary/statement_summary.go b/util/stmtsummary/statement_summary.go index 0ac60f70a1e4a..fc49f53ad474a 100644 --- a/util/stmtsummary/statement_summary.go +++ b/util/stmtsummary/statement_summary.go @@ -515,10 +515,12 @@ func GetBindableStmtFromCluster(rows []chunk.Row) *BindableStmt { Charset: row.GetString(6), //charset Collation: row.GetString(7), //collation } - // If it is SQL command prepare / execute, the ssElement.sampleSQL is `execute ...`, we should get the original select query. + // If it is SQL command prepare / execute, we should remove the arguments // If it is binary protocol prepare / execute, ssbd.normalizedSQL should be same as ssElement.sampleSQL. if row.GetInt64(4) == 1 { - stmt.Query = row.GetString(2) //normalizedSQL + if idx := strings.LastIndex(stmt.Query, "[arguments:"); idx != -1 { + stmt.Query = stmt.Query[:idx] + } } return stmt }