Skip to content

Commit 99fd517

Browse files
authored
*: support logging session connect attrs to slow query log (#66617) (#67323)
close #66616
1 parent 83672a7 commit 99fd517

23 files changed

Lines changed: 1088 additions & 15 deletions

pkg/executor/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ go_test(
466466
"//pkg/testkit/testfailpoint",
467467
"//pkg/testkit/testmain",
468468
"//pkg/testkit/testsetup",
469+
"//pkg/testkit/testutil",
469470
"//pkg/types",
470471
"//pkg/util",
471472
"//pkg/util/benchdaily",

pkg/executor/adapter_slow_log.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,9 @@ func SetSlowLogItems(a *ExecStmt, txnTS uint64, hasMoreResults bool, items *vari
264264
items.CPUUsages = sessVars.SQLCPUUsages.GetCPUUsages()
265265
items.StorageKV = stmtCtx.IsTiKV.Load()
266266
items.StorageMPP = stmtCtx.IsTiFlash.Load()
267+
if sessVars.ConnectionInfo != nil && len(sessVars.ConnectionInfo.Attributes) > 0 {
268+
items.SessionConnectAttrs = sessVars.ConnectionInfo.Attributes
269+
}
267270

268271
if a.retryCount > 0 {
269272
items.ExecRetryTime = items.TimeTotal - sessVars.DurationParse - sessVars.DurationCompile - time.Since(a.retryStartTime)

pkg/executor/cluster_table_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"github.com/pingcap/tidb/pkg/parser/mysql"
3333
"github.com/pingcap/tidb/pkg/server"
3434
"github.com/pingcap/tidb/pkg/testkit"
35+
"github.com/pingcap/tidb/pkg/testkit/testutil"
3536
"github.com/pingcap/tidb/pkg/util"
3637
"github.com/stretchr/testify/require"
3738
"google.golang.org/grpc"
@@ -354,3 +355,38 @@ func removeFiles(t *testing.T, fileNames []string) {
354355
require.NoError(t, os.Remove(fileName))
355356
}
356357
}
358+
359+
func TestClusterTableSlowQuerySessionConnectAttrs(t *testing.T) {
360+
store, dom := testkit.CreateMockStoreAndDomain(t)
361+
srv := createRPCServer(t, dom)
362+
defer srv.Stop()
363+
364+
logData := `
365+
# Time: 2024-01-15T10:00:00.000000+08:00
366+
# Txn_start_ts: 123456789
367+
# User@Host: root[root] @ localhost [127.0.0.1]
368+
# Query_time: 0.5
369+
# Digest: 42a1c8aae6f133e934d4bf0147491709a8812ea05ff8819ec522780fe657b772
370+
# Is_internal: false
371+
# Succ: true
372+
` + testutil.DefaultSessionConnectAttrsSlowLogLine() + `
373+
select * from t;`
374+
fileName := "tidb-slow-query-attrs.log"
375+
prepareLogs(t, []string{logData}, []string{fileName})
376+
defer removeFiles(t, []string{fileName})
377+
378+
defer config.RestoreFunc()()
379+
config.UpdateGlobal(func(conf *config.Config) {
380+
conf.Log.SlowQueryFile = fileName
381+
})
382+
383+
tk := testkit.NewTestKit(t, store)
384+
tk.MustExec("use information_schema")
385+
386+
// Verify Session_connect_attrs column is present in cluster_slow_query as well.
387+
clusterRows := tk.MustQuery("select Session_connect_attrs from information_schema.cluster_slow_query " +
388+
"where time > '2024-01-01 00:00:00' and query = 'select * from t;'").Rows()
389+
require.Len(t, clusterRows, 1)
390+
clusterAttrsStr := clusterRows[0][0].(string)
391+
testutil.RequireContainsDefaultSessionConnectAttrs(t, clusterAttrsStr)
392+
}

pkg/executor/infoschema_reader_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,7 @@ func TestColumnTable(t *testing.T) {
665665
testkit.RowsWithSep("|",
666666
"test|tbl1|col_2"))
667667
tk.MustQuery(`select count(*) from information_schema.columns;`).Check(
668-
testkit.RowsWithSep("|", "5017"))
668+
testkit.RowsWithSep("|", "5019"))
669669
}
670670

671671
func TestIndexUsageTable(t *testing.T) {

pkg/executor/slow_query.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ func (e *slowQueryRetriever) parseSlowLog(ctx context.Context, sctx sessionctx.C
447447
startTime := time.Now()
448448
var logs [][]string
449449
var err error
450-
if !e.extractor.Desc {
450+
if e.extractor == nil || !e.extractor.Desc {
451451
logs, err = e.getBatchLog(ctx, reader, &offset, logNum)
452452
} else {
453453
logs, err = e.getBatchLogForReversedScan(ctx, reader, &offset, logNum)
@@ -703,6 +703,12 @@ func (e *slowQueryRetriever) parseLog(ctx context.Context, sctx sessionctx.Conte
703703
} else if strings.HasPrefix(line, variable.SlowLogWarnings) {
704704
line = line[len(variable.SlowLogWarnings+variable.SlowLogSpaceMarkStr):]
705705
valid = e.setColumnValue(sctx, row, tz, variable.SlowLogWarnings, line, e.checker, fileLine)
706+
} else if strings.HasPrefix(line, variable.SlowLogSessionConnectAttrs+variable.SlowLogSpaceMarkStr) {
707+
line = line[len(variable.SlowLogSessionConnectAttrs+variable.SlowLogSpaceMarkStr):]
708+
valid = e.setColumnValue(sctx, row, tz, variable.SlowLogSessionConnectAttrs, line, e.checker, fileLine)
709+
} else if strings.HasPrefix(line, variable.SlowLogDBStr+variable.SlowLogSpaceMarkStr) {
710+
line = line[len(variable.SlowLogDBStr+variable.SlowLogSpaceMarkStr):]
711+
valid = e.setColumnValue(sctx, row, tz, variable.SlowLogDBStr, line, e.checker, fileLine)
706712
} else {
707713
fields, values := splitByColon(line)
708714
for i := 0; i < len(fields); i++ {
@@ -885,6 +891,18 @@ func getColumnValueFactoryByName(colName string, columnIdx int) (slowQueryColumn
885891
row[columnIdx] = types.NewDatum(v)
886892
return true, nil
887893
}, nil
894+
case variable.SlowLogSessionConnectAttrs:
895+
return func(row []types.Datum, value string, _ *time.Location, _ *slowLogChecker) (valid bool, err error) {
896+
if len(value) == 0 {
897+
return true, nil
898+
}
899+
bj, err := types.ParseBinaryJSONFromString(value)
900+
if err != nil {
901+
return false, err
902+
}
903+
row[columnIdx] = types.NewDatum(bj)
904+
return true, nil
905+
}, nil
888906
}
889907
return nil, nil
890908
}

pkg/executor/slow_query_sql_test.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"github.com/pingcap/tidb/pkg/testkit"
3232
"github.com/pingcap/tidb/pkg/testkit/external"
3333
"github.com/pingcap/tidb/pkg/testkit/testdata"
34+
"github.com/pingcap/tidb/pkg/testkit/testutil"
3435
"github.com/pingcap/tidb/pkg/util/logutil"
3536
"github.com/stretchr/testify/require"
3637
)
@@ -540,3 +541,98 @@ func TestStorageEnginesInSlowQuery(t *testing.T) {
540541
"where query like 'select%tablesample%;'").
541542
Check(testkit.Rows("1 0"))
542543
}
544+
545+
func TestSessionConnectAttrsInSlowQuery(t *testing.T) {
546+
originCfg := config.GetGlobalConfig()
547+
newCfg := *originCfg
548+
f, err := os.CreateTemp("", "tidb-slow-*.log")
549+
require.NoError(t, err)
550+
_, err = f.WriteString(`# Time: 2024-01-15T10:00:00.000000+08:00
551+
# Txn_start_ts: 123456789
552+
# User@Host: root[root] @ localhost [127.0.0.1]
553+
# Query_time: 0.5
554+
# Digest: 42a1c8aae6f133e934d4bf0147491709a8812ea05ff8819ec522780fe657b772
555+
# Is_internal: false
556+
# Succ: true
557+
` + testutil.DefaultSessionConnectAttrsSlowLogLine() + `
558+
select * from t;
559+
`)
560+
require.NoError(t, err)
561+
require.NoError(t, f.Close())
562+
newCfg.Log.SlowQueryFile = f.Name()
563+
config.StoreGlobalConfig(&newCfg)
564+
defer func() {
565+
config.StoreGlobalConfig(originCfg)
566+
require.NoError(t, os.Remove(newCfg.Log.SlowQueryFile))
567+
}()
568+
require.NoError(t, logutil.InitLogger(newCfg.Log.ToLogConfig()))
569+
store := testkit.CreateMockStore(t)
570+
tk := testkit.NewTestKit(t, store)
571+
572+
tk.MustExec("set @@time_zone='+08:00'")
573+
tk.MustExec(fmt.Sprintf("set @@tidb_slow_query_file='%v'", f.Name()))
574+
575+
// Verify Session_connect_attrs column is present and returns the correct JSON value.
576+
rows := tk.MustQuery("select Session_connect_attrs from information_schema.slow_query " +
577+
"where query = 'select * from t;'").Rows()
578+
require.Len(t, rows, 1)
579+
attrsStr := rows[0][0].(string)
580+
testutil.RequireContainsDefaultSessionConnectAttrs(t, attrsStr)
581+
582+
// Verify individual keys are accessible via JSON_EXTRACT.
583+
tk.MustQuery("select JSON_EXTRACT(Session_connect_attrs, '$._client_name') from information_schema.slow_query " +
584+
"where query = 'select * from t;'").
585+
Check(testkit.Rows(`"Go-MySQL-Driver"`))
586+
tk.MustQuery("select JSON_EXTRACT(Session_connect_attrs, '$.app_name') from information_schema.slow_query " +
587+
"where query = 'select * from t;'").
588+
Check(testkit.Rows(`"test_app"`))
589+
}
590+
591+
func TestSessionConnectAttrsMissingAndTruncatedInSlowQuery(t *testing.T) {
592+
originCfg := config.GetGlobalConfig()
593+
newCfg := *originCfg
594+
f, err := os.CreateTemp("", "tidb-slow-*.log")
595+
require.NoError(t, err)
596+
_, err = f.WriteString(`# Time: 2024-01-15T10:00:00.000000+08:00
597+
# Txn_start_ts: 123456789
598+
# User@Host: root[root] @ localhost [127.0.0.1]
599+
# Query_time: 0.5
600+
# Digest: 1111111111111111111111111111111111111111111111111111111111111111
601+
# Is_internal: false
602+
# Succ: true
603+
select * from t_no_attrs;
604+
# Time: 2024-01-15T10:00:01.000000+08:00
605+
# Txn_start_ts: 123456790
606+
# User@Host: root[root] @ localhost [127.0.0.1]
607+
# Query_time: 0.6
608+
# Digest: 2222222222222222222222222222222222222222222222222222222222222222
609+
# Is_internal: false
610+
# Succ: true
611+
# Session_connect_attrs: {"_truncated":"4","app_name":"trunc_case"}
612+
select * from t_truncated;
613+
`)
614+
require.NoError(t, err)
615+
require.NoError(t, f.Close())
616+
newCfg.Log.SlowQueryFile = f.Name()
617+
config.StoreGlobalConfig(&newCfg)
618+
defer func() {
619+
config.StoreGlobalConfig(originCfg)
620+
require.NoError(t, os.Remove(newCfg.Log.SlowQueryFile))
621+
}()
622+
require.NoError(t, logutil.InitLogger(newCfg.Log.ToLogConfig()))
623+
store := testkit.CreateMockStore(t)
624+
tk := testkit.NewTestKit(t, store)
625+
626+
tk.MustExec("set @@time_zone='+08:00'")
627+
tk.MustExec(fmt.Sprintf("set @@tidb_slow_query_file='%v'", f.Name()))
628+
629+
// Missing Session_connect_attrs should parse to JSON null-like empty behavior.
630+
tk.MustQuery("select Session_connect_attrs = cast('null' as json), JSON_EXTRACT(Session_connect_attrs, '$._truncated') is null from information_schema.slow_query " +
631+
"where query = 'select * from t_no_attrs;' ").
632+
Check(testkit.Rows("1 1"))
633+
634+
// Truncation metadata key should be preserved and queryable from JSON.
635+
tk.MustQuery("select JSON_UNQUOTE(JSON_EXTRACT(Session_connect_attrs, '$._truncated')), JSON_UNQUOTE(JSON_EXTRACT(Session_connect_attrs, '$.app_name')) from information_schema.slow_query " +
636+
"where query = 'select * from t_truncated;' ").
637+
Check(testkit.Rows("4 trunc_case"))
638+
}

pkg/executor/slow_query_test.go

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
plannercore "github.com/pingcap/tidb/pkg/planner/core"
3636
"github.com/pingcap/tidb/pkg/sessionctx"
3737
"github.com/pingcap/tidb/pkg/sessionctx/variable"
38+
"github.com/pingcap/tidb/pkg/testkit/testutil"
3839
"github.com/pingcap/tidb/pkg/types"
3940
"github.com/pingcap/tidb/pkg/util"
4041
"github.com/pingcap/tidb/pkg/util/logutil"
@@ -178,7 +179,7 @@ select * from t;`
178179
`0.1,0.2,0.03,127.0.0.1:20160,0.05,0.6,0.8,0.0.0.0:20160,70724,65536,0,0,0,0,0,,` +
179180
`Cop_backoff_regionMiss_total_times: 200 Cop_backoff_regionMiss_total_time: 0.2 Cop_backoff_regionMiss_max_time: 0.2 Cop_backoff_regionMiss_max_addr: 127.0.0.1 Cop_backoff_regionMiss_avg_time: 0.2 Cop_backoff_regionMiss_p90_time: 0.2 Cop_backoff_rpcPD_total_times: 200 Cop_backoff_rpcPD_total_time: 0.2 Cop_backoff_rpcPD_max_time: 0.2 Cop_backoff_rpcPD_max_addr: 127.0.0.1 Cop_backoff_rpcPD_avg_time: 0.2 Cop_backoff_rpcPD_p90_time: 0.2 Cop_backoff_rpcTiKV_total_times: 200 Cop_backoff_rpcTiKV_total_time: 0.2 Cop_backoff_rpcTiKV_max_time: 0.2 Cop_backoff_rpcTiKV_max_addr: 127.0.0.1 Cop_backoff_rpcTiKV_avg_time: 0.2 Cop_backoff_rpcTiKV_p90_time: 0.2,` +
180181
`0,0,1,0,1,1,0,default,2.158,2.123,0.05,0.01,0.021,1,1,,60e9378c746d9a2be1c791047e008967cf252eb6de9167ad3aa6098fa2d523f4,` +
181-
`,update t set i = 1;,select * from t;`
182+
`,update t set i = 1;,null,select * from t;`
182183
require.Equal(t, expectRecordString, recordString)
183184

184185
// Issue 20928
@@ -201,7 +202,7 @@ select * from t;`
201202
`0.1,0.2,0.03,127.0.0.1:20160,0.05,0.6,0.8,0.0.0.0:20160,70724,65536,0,0,0,0,0,,` +
202203
`Cop_backoff_regionMiss_total_times: 200 Cop_backoff_regionMiss_total_time: 0.2 Cop_backoff_regionMiss_max_time: 0.2 Cop_backoff_regionMiss_max_addr: 127.0.0.1 Cop_backoff_regionMiss_avg_time: 0.2 Cop_backoff_regionMiss_p90_time: 0.2 Cop_backoff_rpcPD_total_times: 200 Cop_backoff_rpcPD_total_time: 0.2 Cop_backoff_rpcPD_max_time: 0.2 Cop_backoff_rpcPD_max_addr: 127.0.0.1 Cop_backoff_rpcPD_avg_time: 0.2 Cop_backoff_rpcPD_p90_time: 0.2 Cop_backoff_rpcTiKV_total_times: 200 Cop_backoff_rpcTiKV_total_time: 0.2 Cop_backoff_rpcTiKV_max_time: 0.2 Cop_backoff_rpcTiKV_max_addr: 127.0.0.1 Cop_backoff_rpcTiKV_avg_time: 0.2 Cop_backoff_rpcTiKV_p90_time: 0.2,` +
203204
`0,0,1,0,1,1,0,default,2.158,2.123,0.05,0.01,0.021,1,1,,60e9378c746d9a2be1c791047e008967cf252eb6de9167ad3aa6098fa2d523f4,` +
204-
`,update t set i = 1;,select * from t;`
205+
`,update t set i = 1;,null,select * from t;`
205206
require.Equal(t, expectRecordString, recordString)
206207

207208
// fix sql contain '# ' bug
@@ -254,6 +255,57 @@ select * from t;
254255
require.Equal(t, warnings[0].Err.Error(), "Parse slow log at line 2, failed field is Succ, failed value is abc, error is strconv.ParseBool: parsing \"abc\": invalid syntax")
255256
}
256257

258+
func TestParseSlowLogSessionConnectAttrs(t *testing.T) {
259+
// Slow log entry that includes Session_connect_attrs JSON.
260+
slowLogStr := `# Time: 2019-04-28T15:24:04.309074+08:00
261+
# Txn_start_ts: 405888132465033227
262+
# User@Host: root[root] @ localhost [127.0.0.1]
263+
# Query_time: 0.216905
264+
# Digest: 42a1c8aae6f133e934d4bf0147491709a8812ea05ff8819ec522780fe657b772
265+
# Is_internal: false
266+
# Succ: true
267+
` + testutil.DefaultSessionConnectAttrsSlowLogLine() + `
268+
# Prev_stmt: begin;
269+
select * from t;
270+
`
271+
loc, err := time.LoadLocation("Asia/Shanghai")
272+
require.NoError(t, err)
273+
ctx := mock.NewContext()
274+
ctx.ResetSessionAndStmtTimeZone(loc)
275+
276+
// Use the retriever directly (without initialize) to avoid reading
277+
// from actual slow log files on disk, which can produce extra rows.
278+
retriever, err := newSlowQueryRetriever()
279+
require.NoError(t, err)
280+
retriever.columnValueFactoryMap = make(map[string]slowQueryColumnValueFactory, len(retriever.outputCols))
281+
for idx, col := range retriever.outputCols {
282+
factory, err := getColumnValueFactoryByName(col.Name.O, idx)
283+
require.NoError(t, err)
284+
require.NotNil(t, factory, "column %s should have a factory", col.Name.O)
285+
retriever.columnValueFactoryMap[col.Name.O] = factory
286+
}
287+
288+
reader := bufio.NewReader(bytes.NewBufferString(slowLogStr))
289+
rows, err := parseLog(retriever, ctx, reader)
290+
require.NoError(t, err)
291+
require.Len(t, rows, 1)
292+
293+
// Find the Session_connect_attrs column.
294+
colIdx := -1
295+
for i, col := range retriever.outputCols {
296+
if col.Name.L == strings.ToLower(variable.SlowLogSessionConnectAttrs) {
297+
colIdx = i
298+
break
299+
}
300+
}
301+
require.NotEqual(t, -1, colIdx, "Session_connect_attrs column should exist")
302+
303+
// Verify the parsed JSON contains the expected keys.
304+
bj := rows[0][colIdx].GetMysqlJSON()
305+
bjStr := bj.String()
306+
testutil.RequireContainsDefaultSessionConnectAttrs(t, bjStr)
307+
}
308+
257309
// It changes variable.MaxOfMaxAllowedPacket, so must be stayed in SerialSuite.
258310
func TestParseSlowLogFileSerial(t *testing.T) {
259311
loc, err := time.LoadLocation("Asia/Shanghai")

pkg/infoschema/tables.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,7 @@ var slowQueryCols = []columnInfo{
971971
{name: variable.SlowLogPlanDigest, tp: mysql.TypeVarchar, size: 128},
972972
{name: variable.SlowLogBinaryPlan, tp: mysql.TypeLongBlob, size: types.UnspecifiedLength},
973973
{name: variable.SlowLogPrevStmt, tp: mysql.TypeLongBlob, size: types.UnspecifiedLength},
974+
{name: variable.SlowLogSessionConnectAttrs, tp: mysql.TypeJSON, size: types.UnspecifiedLength},
974975
{name: variable.SlowLogQuerySQLStr, tp: mysql.TypeLongBlob, size: types.UnspecifiedLength},
975976
}
976977

pkg/infoschema/test/clustertablestest/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ go_test(
3838
"//pkg/testkit",
3939
"//pkg/testkit/external",
4040
"//pkg/testkit/testsetup",
41+
"//pkg/testkit/testutil",
4142
"//pkg/types",
4243
"//pkg/util",
4344
"//pkg/util/dbterror/exeerrors",

pkg/infoschema/test/clustertablestest/cluster_tables_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import (
5050
"github.com/pingcap/tidb/pkg/store/mockstore/unistore"
5151
"github.com/pingcap/tidb/pkg/testkit"
5252
"github.com/pingcap/tidb/pkg/testkit/external"
53+
"github.com/pingcap/tidb/pkg/testkit/testutil"
5354
"github.com/pingcap/tidb/pkg/util"
5455
"github.com/pingcap/tidb/pkg/util/dbterror/exeerrors"
5556
"github.com/pingcap/tidb/pkg/util/logutil"
@@ -293,6 +294,55 @@ func TestSelectClusterTable(t *testing.T) {
293294
tk.MustQuery("select instance from `CLUSTER_SLOW_QUERY` where time='2019-02-12 19:33:56.571953'").Check(testkit.Rows(instanceAddr))
294295
}
295296

297+
func TestClusterSlowQuerySessionConnectAttrs(t *testing.T) {
298+
// setup suite
299+
s := new(clusterTablesSuite)
300+
s.store, s.dom = testkit.CreateMockStoreAndDomain(t)
301+
s.rpcserver, s.listenAddr = s.setUpRPCService(t, "127.0.0.1:0", nil)
302+
s.httpServer, s.mockAddr = s.setUpMockPDHTTPServer()
303+
s.startTime = time.Now()
304+
defer s.httpServer.Close()
305+
defer s.rpcserver.Stop()
306+
307+
f, err := os.CreateTemp("", "tidb-cluster-slow-*.log")
308+
require.NoError(t, err)
309+
_, err = f.WriteString(`# Time: 2024-01-15T10:00:00.000000+08:00
310+
# Txn_start_ts: 123456789
311+
# User@Host: root[root] @ localhost [127.0.0.1]
312+
# Query_time: 0.5
313+
# Digest: 42a1c8aae6f133e934d4bf0147491709a8812ea05ff8819ec522780fe657b772
314+
# Is_internal: false
315+
# Succ: true
316+
` + testutil.DefaultSessionConnectAttrsSlowLogLine() + `
317+
select * from t;
318+
`)
319+
require.NoError(t, err)
320+
require.NoError(t, f.Close())
321+
defer func() { require.NoError(t, os.Remove(f.Name())) }()
322+
323+
defer config.RestoreFunc()()
324+
config.UpdateGlobal(func(conf *config.Config) {
325+
conf.Log.SlowQueryFile = f.Name()
326+
})
327+
328+
tk := s.newTestKitWithRoot(t)
329+
tk.MustExec("use information_schema")
330+
tk.MustExec("set time_zone = '+08:00';")
331+
332+
rows := tk.MustQuery("select Session_connect_attrs from information_schema.cluster_slow_query " +
333+
"where query = 'select * from t;'").Rows()
334+
require.Len(t, rows, 1)
335+
attrsStr := rows[0][0].(string)
336+
testutil.RequireContainsDefaultSessionConnectAttrs(t, attrsStr)
337+
338+
tk.MustQuery("select JSON_EXTRACT(Session_connect_attrs, '$._client_name') from information_schema.cluster_slow_query " +
339+
"where query = 'select * from t;'").
340+
Check(testkit.Rows(`"Go-MySQL-Driver"`))
341+
tk.MustQuery("select JSON_EXTRACT(Session_connect_attrs, '$.app_name') from information_schema.cluster_slow_query " +
342+
"where query = 'select * from t;'").
343+
Check(testkit.Rows(`"test_app"`))
344+
}
345+
296346
func TestSelectClusterTablePrivilege(t *testing.T) {
297347
// setup suite
298348
s := new(clusterTablesSuite)

0 commit comments

Comments
 (0)