@@ -24,6 +24,8 @@ import (
2424
2525 rmpb "github.com/pingcap/kvproto/pkg/resource_manager"
2626 "github.com/pingcap/tidb/pkg/config"
27+ "github.com/pingcap/tidb/pkg/meta/model"
28+ "github.com/pingcap/tidb/pkg/parser/ast"
2729 "github.com/pingcap/tidb/pkg/parser/mysql"
2830 "github.com/pingcap/tidb/pkg/planner/core/resolve"
2931 "github.com/pingcap/tidb/pkg/server/internal"
@@ -86,6 +88,35 @@ func (*firstNextErrRecordSet) Close() error { return nil }
8688
8789var _ sqlexec.RecordSet = & firstNextErrRecordSet {}
8890
91+ type singleRowCursorRecordSet struct {
92+ returned bool
93+ }
94+
95+ func (* singleRowCursorRecordSet ) Fields () []* resolve.ResultField {
96+ return []* resolve.ResultField {{
97+ Column : & model.ColumnInfo {Name : ast .NewCIStr ("a" ), FieldType : * types .NewFieldType (mysql .TypeLonglong )},
98+ ColumnAsName : ast .NewCIStr ("a" ),
99+ }}
100+ }
101+
102+ func (rs * singleRowCursorRecordSet ) Next (_ context.Context , chk * chunk.Chunk ) error {
103+ chk .Reset ()
104+ if rs .returned {
105+ return nil
106+ }
107+ chk .AppendInt64 (0 , 1 )
108+ rs .returned = true
109+ return nil
110+ }
111+
112+ func (* singleRowCursorRecordSet ) NewChunk (chunk.Allocator ) * chunk.Chunk {
113+ return chunk .NewChunkWithCapacity ([]* types.FieldType {types .NewFieldType (mysql .TypeLonglong )}, 1 )
114+ }
115+
116+ func (* singleRowCursorRecordSet ) Close () error { return nil }
117+
118+ var _ sqlexec.RecordSet = & singleRowCursorRecordSet {}
119+
89120func TestCursorExistsFlag (t * testing.T ) {
90121 store , dom := testkit .CreateMockStoreAndDomain (t )
91122 srv := CreateMockServer (t , store )
@@ -225,6 +256,27 @@ func TestCursorWithParams(t *testing.T) {
225256 require .Zero (t , execdetails .RUV2MetricsFromContext (ctx ).ResultChunkCells ())
226257 })
227258
259+ t .Run ("write chunks with fetch size records result chunk cells once" , func (t * testing.T ) {
260+ store , dom := testkit .CreateMockStoreAndDomain (t )
261+ srv := CreateMockServer (t , store )
262+ srv .SetDomain (dom )
263+ defer srv .Close ()
264+
265+ c := CreateMockConn (t , srv ).(* mockConn )
266+ ctx := execdetails .ContextWithInitializedExecDetails (context .Background ())
267+ ruv2Metrics := execdetails .RUV2MetricsFromContext (ctx )
268+ require .NotNil (t , ruv2Metrics )
269+
270+ rs := resultset .New (& singleRowCursorRecordSet {}, nil )
271+ cursorRS := resultset .WrapWithLazyCursor (rs , 1 , 1 )
272+ tracker := resultset .NewCursorRUV2Tracker (nil , "" , ruv2Metrics , nil , execdetails.RUV2Weights {})
273+ resultset .AttachCursorRUV2Tracker (cursorRS , tracker )
274+
275+ err := c .writeChunksWithFetchSize (ctx , cursorRS , mysql .ServerStatusAutocommit , 1 )
276+ require .NoError (t , err )
277+ require .Equal (t , int64 (1 ), ruv2Metrics .ResultChunkCells ())
278+ })
279+
228280 store , dom := testkit .CreateMockStoreAndDomain (t )
229281 srv := CreateMockServer (t , store )
230282 srv .SetDomain (dom )
0 commit comments