@@ -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.
258310func TestParseSlowLogFileSerial (t * testing.T ) {
259311 loc , err := time .LoadLocation ("Asia/Shanghai" )
0 commit comments