github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/interlock/aggfuncs/aggfunc_test.go (about) 1 // Copyright 2020 WHTCORPS INC, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package aggfuncs_test 15 16 import ( 17 "fmt" 18 "strconv" 19 "testing" 20 "time" 21 "unsafe" 22 23 "github.com/dgryski/go-farm" 24 "github.com/whtcorpsinc/BerolinaSQL" 25 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 26 "github.com/whtcorpsinc/BerolinaSQL/ast" 27 . "github.com/whtcorpsinc/check" 28 "github.com/whtcorpsinc/errors" 29 "github.com/whtcorpsinc/milevadb/causet/soliton" 30 "github.com/whtcorpsinc/milevadb/causetstore/mockstore" 31 "github.com/whtcorpsinc/milevadb/causetstore/mockstore/cluster" 32 "github.com/whtcorpsinc/milevadb/ekv" 33 "github.com/whtcorpsinc/milevadb/interlock/aggfuncs" 34 "github.com/whtcorpsinc/milevadb/memex" 35 "github.com/whtcorpsinc/milevadb/memex/aggregation" 36 "github.com/whtcorpsinc/milevadb/petri" 37 "github.com/whtcorpsinc/milevadb/soliton/chunk" 38 "github.com/whtcorpsinc/milevadb/soliton/codec" 39 "github.com/whtcorpsinc/milevadb/soliton/mock" 40 "github.com/whtcorpsinc/milevadb/soliton/replog" 41 "github.com/whtcorpsinc/milevadb/soliton/set" 42 "github.com/whtcorpsinc/milevadb/stochastik" 43 "github.com/whtcorpsinc/milevadb/stochastikctx" 44 "github.com/whtcorpsinc/milevadb/types" 45 "github.com/whtcorpsinc/milevadb/types/json" 46 ) 47 48 var _ = Suite(&testSuite{}) 49 50 func TestT(t *testing.T) { 51 CustomVerboseFlag = true 52 *CustomParallelSuiteFlag = true 53 TestingT(t) 54 } 55 56 type testSuite struct { 57 *BerolinaSQL.BerolinaSQL 58 ctx stochastikctx.Context 59 cluster cluster.Cluster 60 causetstore ekv.CausetStorage 61 petri *petri.Petri 62 } 63 64 func (s *testSuite) SetUpSuite(c *C) { 65 s.BerolinaSQL = BerolinaSQL.New() 66 s.ctx = mock.NewContext() 67 s.ctx.GetStochastikVars().StmtCtx.TimeZone = time.Local 68 causetstore, err := mockstore.NewMockStore( 69 mockstore.WithClusterInspector(func(c cluster.Cluster) { 70 mockstore.BootstrapWithSingleStore(c) 71 s.cluster = c 72 }), 73 ) 74 c.Assert(err, IsNil) 75 s.causetstore = causetstore 76 d, err := stochastik.BootstrapStochastik(s.causetstore) 77 c.Assert(err, IsNil) 78 d.SetStatsUFIDelating(true) 79 s.petri = d 80 } 81 82 func (s *testSuite) TearDownSuite(c *C) { 83 } 84 85 func (s *testSuite) SetUpTest(c *C) { 86 s.ctx.GetStochastikVars().CausetDeferredCausetID = 0 87 } 88 89 func (s *testSuite) TearDownTest(c *C) { 90 s.ctx.GetStochastikVars().StmtCtx.SetWarnings(nil) 91 } 92 93 type aggTest struct { 94 dataType *types.FieldType 95 numEvents int 96 dataGen func(i int) types.Causet 97 funcName string 98 results []types.Causet 99 orderBy bool 100 } 101 102 func (p *aggTest) genSrcChk() *chunk.Chunk { 103 srcChk := chunk.NewChunkWithCapacity([]*types.FieldType{p.dataType}, p.numEvents) 104 for i := 0; i < p.numEvents; i++ { 105 dt := p.dataGen(i) 106 srcChk.AppendCauset(0, &dt) 107 } 108 srcChk.AppendCauset(0, &types.Causet{}) 109 return srcChk 110 } 111 112 // messUpChunk messes up the chunk for testing memory reference. 113 func (p *aggTest) messUpChunk(c *chunk.Chunk) { 114 for i := 0; i < p.numEvents; i++ { 115 raw := c.DeferredCauset(0).GetRaw(i) 116 for i := range raw { 117 raw[i] = 255 118 } 119 } 120 } 121 122 type multiArgsAggTest struct { 123 dataTypes []*types.FieldType 124 retType *types.FieldType 125 numEvents int 126 dataGens []func(i int) types.Causet 127 funcName string 128 results []types.Causet 129 orderBy bool 130 } 131 132 func (p *multiArgsAggTest) genSrcChk() *chunk.Chunk { 133 srcChk := chunk.NewChunkWithCapacity(p.dataTypes, p.numEvents) 134 for i := 0; i < p.numEvents; i++ { 135 for j := 0; j < len(p.dataGens); j++ { 136 fdt := p.dataGens[j](i) 137 srcChk.AppendCauset(j, &fdt) 138 } 139 } 140 srcChk.AppendCauset(0, &types.Causet{}) 141 return srcChk 142 } 143 144 // messUpChunk messes up the chunk for testing memory reference. 145 func (p *multiArgsAggTest) messUpChunk(c *chunk.Chunk) { 146 for i := 0; i < p.numEvents; i++ { 147 for j := 0; j < len(p.dataGens); j++ { 148 raw := c.DeferredCauset(j).GetRaw(i) 149 for i := range raw { 150 raw[i] = 255 151 } 152 } 153 } 154 } 155 156 type uFIDelateMemDeltaGens func(*chunk.Chunk, *types.FieldType) (memDeltas []int64, err error) 157 158 func defaultUFIDelateMemDeltaGens(srcChk *chunk.Chunk, dataType *types.FieldType) (memDeltas []int64, err error) { 159 memDeltas = make([]int64, 0) 160 for i := 0; i < srcChk.NumEvents(); i++ { 161 memDeltas = append(memDeltas, int64(0)) 162 } 163 return memDeltas, nil 164 } 165 166 func approxCountDistinctUFIDelateMemDeltaGens(srcChk *chunk.Chunk, dataType *types.FieldType) (memDeltas []int64, err error) { 167 memDeltas = make([]int64, 0) 168 169 buf := make([]byte, 8) 170 p := aggfuncs.NewPartialResult4ApproxCountDistinct() 171 for i := 0; i < srcChk.NumEvents(); i++ { 172 event := srcChk.GetEvent(i) 173 if event.IsNull(0) { 174 memDeltas = append(memDeltas, int64(0)) 175 continue 176 } 177 oldMemUsage := p.MemUsage() 178 switch dataType.Tp { 179 case allegrosql.TypeLonglong: 180 val := event.GetInt64(0) 181 *(*int64)(unsafe.Pointer(&buf[0])) = val 182 case allegrosql.TypeString: 183 val := event.GetString(0) 184 buf = codec.EncodeCompactBytes(buf, replog.Slice(val)) 185 default: 186 return memDeltas, errors.Errorf("unsupported type - %v", dataType.Tp) 187 } 188 189 x := farm.Hash64(buf) 190 p.InsertHash64(x) 191 newMemUsage := p.MemUsage() 192 memDelta := newMemUsage - oldMemUsage 193 memDeltas = append(memDeltas, memDelta) 194 } 195 return memDeltas, nil 196 } 197 198 func distinctUFIDelateMemDeltaGens(srcChk *chunk.Chunk, dataType *types.FieldType) (memDeltas []int64, err error) { 199 valSet := set.NewStringSet() 200 memDeltas = make([]int64, 0) 201 for i := 0; i < srcChk.NumEvents(); i++ { 202 event := srcChk.GetEvent(i) 203 if event.IsNull(0) { 204 memDeltas = append(memDeltas, int64(0)) 205 continue 206 } 207 val := "" 208 memDelta := int64(0) 209 switch dataType.Tp { 210 case allegrosql.TypeLonglong: 211 val = strconv.FormatInt(event.GetInt64(0), 10) 212 memDelta = aggfuncs.DefInt64Size 213 case allegrosql.TypeFloat: 214 val = strconv.FormatFloat(float64(event.GetFloat32(0)), 'f', 6, 64) 215 memDelta = aggfuncs.DefFloat64Size 216 case allegrosql.TypeDouble: 217 val = strconv.FormatFloat(event.GetFloat64(0), 'f', 6, 64) 218 memDelta = aggfuncs.DefFloat64Size 219 case allegrosql.TypeNewDecimal: 220 decimal := event.GetMyDecimal(0) 221 hash, err := decimal.ToHashKey() 222 if err != nil { 223 memDeltas = append(memDeltas, int64(0)) 224 continue 225 } 226 val = string(replog.String(hash)) 227 memDelta = int64(len(val)) 228 case allegrosql.TypeString: 229 val = event.GetString(0) 230 memDelta = int64(len(val)) 231 case allegrosql.TypeDate: 232 val = event.GetTime(0).String() 233 memDelta = aggfuncs.DefTimeSize 234 case allegrosql.TypeDuration: 235 val = strconv.FormatInt(event.GetInt64(0), 10) 236 memDelta = aggfuncs.DefInt64Size 237 case allegrosql.TypeJSON: 238 jsonVal := event.GetJSON(0) 239 bytes := make([]byte, 0) 240 bytes = append(bytes, jsonVal.TypeCode) 241 bytes = append(bytes, jsonVal.Value...) 242 val = string(bytes) 243 memDelta = int64(len(val)) 244 default: 245 return memDeltas, errors.Errorf("unsupported type - %v", dataType.Tp) 246 } 247 if valSet.Exist(val) { 248 memDeltas = append(memDeltas, int64(0)) 249 continue 250 } 251 valSet.Insert(val) 252 memDeltas = append(memDeltas, memDelta) 253 } 254 return memDeltas, nil 255 } 256 257 func rowMemDeltaGens(srcChk *chunk.Chunk, dataType *types.FieldType) (memDeltas []int64, err error) { 258 memDeltas = make([]int64, 0) 259 for i := 0; i < srcChk.NumEvents(); i++ { 260 memDelta := aggfuncs.DefEventSize 261 memDeltas = append(memDeltas, memDelta) 262 } 263 return memDeltas, nil 264 } 265 266 type aggMemTest struct { 267 aggTest aggTest 268 allocMemDelta int64 269 uFIDelateMemDeltaGens uFIDelateMemDeltaGens 270 isDistinct bool 271 } 272 273 func builPosetDaggMemTester(funcName string, tp byte, numEvents int, allocMemDelta int64, uFIDelateMemDeltaGens uFIDelateMemDeltaGens, isDistinct bool) aggMemTest { 274 aggTest := builPosetDaggTester(funcName, tp, numEvents) 275 pt := aggMemTest{ 276 aggTest: aggTest, 277 allocMemDelta: allocMemDelta, 278 uFIDelateMemDeltaGens: uFIDelateMemDeltaGens, 279 isDistinct: isDistinct, 280 } 281 return pt 282 } 283 284 func (s *testSuite) testMergePartialResult(c *C, p aggTest) { 285 srcChk := p.genSrcChk() 286 iter := chunk.NewIterator4Chunk(srcChk) 287 288 args := []memex.Expression{&memex.DeferredCauset{RetType: p.dataType, Index: 0}} 289 if p.funcName == ast.AggFuncGroupConcat { 290 args = append(args, &memex.Constant{Value: types.NewStringCauset(" "), RetType: types.NewFieldType(allegrosql.TypeString)}) 291 } 292 desc, err := aggregation.NewAggFuncDesc(s.ctx, p.funcName, args, false) 293 c.Assert(err, IsNil) 294 if p.orderBy { 295 desc.OrderByItems = []*soliton.ByItems{ 296 {Expr: args[0], Desc: true}, 297 } 298 } 299 partialDesc, finalDesc := desc.Split([]int{0, 1}) 300 301 // build partial func for partial phase. 302 partialFunc := aggfuncs.Build(s.ctx, partialDesc, 0) 303 partialResult, _ := partialFunc.AllocPartialResult() 304 305 // build final func for final phase. 306 finalFunc := aggfuncs.Build(s.ctx, finalDesc, 0) 307 finalPr, _ := finalFunc.AllocPartialResult() 308 resultChk := chunk.NewChunkWithCapacity([]*types.FieldType{p.dataType}, 1) 309 if p.funcName == ast.AggFuncApproxCountDistinct { 310 resultChk = chunk.NewChunkWithCapacity([]*types.FieldType{types.NewFieldType(allegrosql.TypeString)}, 1) 311 } 312 313 // uFIDelate partial result. 314 for event := iter.Begin(); event != iter.End(); event = iter.Next() { 315 partialFunc.UFIDelatePartialResult(s.ctx, []chunk.Event{event}, partialResult) 316 } 317 p.messUpChunk(srcChk) 318 partialFunc.AppendFinalResult2Chunk(s.ctx, partialResult, resultChk) 319 dt := resultChk.GetEvent(0).GetCauset(0, p.dataType) 320 if p.funcName == ast.AggFuncApproxCountDistinct { 321 dt = resultChk.GetEvent(0).GetCauset(0, types.NewFieldType(allegrosql.TypeString)) 322 } 323 result, err := dt.CompareCauset(s.ctx.GetStochastikVars().StmtCtx, &p.results[0]) 324 c.Assert(err, IsNil) 325 c.Assert(result, Equals, 0, Commentf("%v != %v", dt.String(), p.results[0])) 326 327 _, err = finalFunc.MergePartialResult(s.ctx, partialResult, finalPr) 328 c.Assert(err, IsNil) 329 partialFunc.ResetPartialResult(partialResult) 330 331 srcChk = p.genSrcChk() 332 iter = chunk.NewIterator4Chunk(srcChk) 333 iter.Begin() 334 iter.Next() 335 for event := iter.Next(); event != iter.End(); event = iter.Next() { 336 partialFunc.UFIDelatePartialResult(s.ctx, []chunk.Event{event}, partialResult) 337 } 338 p.messUpChunk(srcChk) 339 resultChk.Reset() 340 partialFunc.AppendFinalResult2Chunk(s.ctx, partialResult, resultChk) 341 dt = resultChk.GetEvent(0).GetCauset(0, p.dataType) 342 if p.funcName == ast.AggFuncApproxCountDistinct { 343 dt = resultChk.GetEvent(0).GetCauset(0, types.NewFieldType(allegrosql.TypeString)) 344 } 345 result, err = dt.CompareCauset(s.ctx.GetStochastikVars().StmtCtx, &p.results[1]) 346 c.Assert(err, IsNil) 347 c.Assert(result, Equals, 0, Commentf("%v != %v", dt.String(), p.results[1])) 348 _, err = finalFunc.MergePartialResult(s.ctx, partialResult, finalPr) 349 c.Assert(err, IsNil) 350 351 if p.funcName == ast.AggFuncApproxCountDistinct { 352 resultChk = chunk.NewChunkWithCapacity([]*types.FieldType{types.NewFieldType(allegrosql.TypeLonglong)}, 1) 353 } 354 resultChk.Reset() 355 err = finalFunc.AppendFinalResult2Chunk(s.ctx, finalPr, resultChk) 356 c.Assert(err, IsNil) 357 358 dt = resultChk.GetEvent(0).GetCauset(0, p.dataType) 359 if p.funcName == ast.AggFuncApproxCountDistinct { 360 dt = resultChk.GetEvent(0).GetCauset(0, types.NewFieldType(allegrosql.TypeLonglong)) 361 } 362 result, err = dt.CompareCauset(s.ctx.GetStochastikVars().StmtCtx, &p.results[2]) 363 c.Assert(err, IsNil) 364 c.Assert(result, Equals, 0, Commentf("%v != %v", dt.String(), p.results[2])) 365 } 366 367 func builPosetDaggTester(funcName string, tp byte, numEvents int, results ...interface{}) aggTest { 368 return builPosetDaggTesterWithFieldType(funcName, types.NewFieldType(tp), numEvents, results...) 369 } 370 371 func builPosetDaggTesterWithFieldType(funcName string, ft *types.FieldType, numEvents int, results ...interface{}) aggTest { 372 pt := aggTest{ 373 dataType: ft, 374 numEvents: numEvents, 375 funcName: funcName, 376 dataGen: getDataGenFunc(ft), 377 } 378 for _, result := range results { 379 pt.results = append(pt.results, types.NewCauset(result)) 380 } 381 return pt 382 } 383 384 func (s *testSuite) testMultiArgsMergePartialResult(c *C, p multiArgsAggTest) { 385 srcChk := p.genSrcChk() 386 iter := chunk.NewIterator4Chunk(srcChk) 387 388 args := make([]memex.Expression, len(p.dataTypes)) 389 for k := 0; k < len(p.dataTypes); k++ { 390 args[k] = &memex.DeferredCauset{RetType: p.dataTypes[k], Index: k} 391 } 392 393 desc, err := aggregation.NewAggFuncDesc(s.ctx, p.funcName, args, false) 394 c.Assert(err, IsNil) 395 if p.orderBy { 396 desc.OrderByItems = []*soliton.ByItems{ 397 {Expr: args[0], Desc: true}, 398 } 399 } 400 partialDesc, finalDesc := desc.Split([]int{0, 1}) 401 402 // build partial func for partial phase. 403 partialFunc := aggfuncs.Build(s.ctx, partialDesc, 0) 404 partialResult, _ := partialFunc.AllocPartialResult() 405 406 // build final func for final phase. 407 finalFunc := aggfuncs.Build(s.ctx, finalDesc, 0) 408 finalPr, _ := finalFunc.AllocPartialResult() 409 resultChk := chunk.NewChunkWithCapacity([]*types.FieldType{p.retType}, 1) 410 411 // uFIDelate partial result. 412 for event := iter.Begin(); event != iter.End(); event = iter.Next() { 413 partialFunc.UFIDelatePartialResult(s.ctx, []chunk.Event{event}, partialResult) 414 } 415 p.messUpChunk(srcChk) 416 partialFunc.AppendFinalResult2Chunk(s.ctx, partialResult, resultChk) 417 dt := resultChk.GetEvent(0).GetCauset(0, p.retType) 418 result, err := dt.CompareCauset(s.ctx.GetStochastikVars().StmtCtx, &p.results[0]) 419 c.Assert(err, IsNil) 420 c.Assert(result, Equals, 0) 421 422 _, err = finalFunc.MergePartialResult(s.ctx, partialResult, finalPr) 423 c.Assert(err, IsNil) 424 partialFunc.ResetPartialResult(partialResult) 425 426 srcChk = p.genSrcChk() 427 iter = chunk.NewIterator4Chunk(srcChk) 428 iter.Begin() 429 iter.Next() 430 for event := iter.Next(); event != iter.End(); event = iter.Next() { 431 partialFunc.UFIDelatePartialResult(s.ctx, []chunk.Event{event}, partialResult) 432 } 433 p.messUpChunk(srcChk) 434 resultChk.Reset() 435 partialFunc.AppendFinalResult2Chunk(s.ctx, partialResult, resultChk) 436 dt = resultChk.GetEvent(0).GetCauset(0, p.retType) 437 result, err = dt.CompareCauset(s.ctx.GetStochastikVars().StmtCtx, &p.results[1]) 438 c.Assert(err, IsNil) 439 c.Assert(result, Equals, 0) 440 _, err = finalFunc.MergePartialResult(s.ctx, partialResult, finalPr) 441 c.Assert(err, IsNil) 442 443 resultChk.Reset() 444 err = finalFunc.AppendFinalResult2Chunk(s.ctx, finalPr, resultChk) 445 c.Assert(err, IsNil) 446 447 dt = resultChk.GetEvent(0).GetCauset(0, p.retType) 448 result, err = dt.CompareCauset(s.ctx.GetStochastikVars().StmtCtx, &p.results[2]) 449 c.Assert(err, IsNil) 450 c.Assert(result, Equals, 0) 451 } 452 453 // for multiple args in aggfuncs such as json_objectagg(c1, c2) 454 func buildMultiArgsAggTester(funcName string, tps []byte, rt byte, numEvents int, results ...interface{}) multiArgsAggTest { 455 fts := make([]*types.FieldType, len(tps)) 456 for i := 0; i < len(tps); i++ { 457 fts[i] = types.NewFieldType(tps[i]) 458 } 459 return buildMultiArgsAggTesterWithFieldType(funcName, fts, types.NewFieldType(rt), numEvents, results...) 460 } 461 462 func buildMultiArgsAggTesterWithFieldType(funcName string, fts []*types.FieldType, rt *types.FieldType, numEvents int, results ...interface{}) multiArgsAggTest { 463 dataGens := make([]func(i int) types.Causet, len(fts)) 464 for i := 0; i < len(fts); i++ { 465 dataGens[i] = getDataGenFunc(fts[i]) 466 } 467 mt := multiArgsAggTest{ 468 dataTypes: fts, 469 retType: rt, 470 numEvents: numEvents, 471 funcName: funcName, 472 dataGens: dataGens, 473 } 474 for _, result := range results { 475 mt.results = append(mt.results, types.NewCauset(result)) 476 } 477 return mt 478 } 479 480 func getDataGenFunc(ft *types.FieldType) func(i int) types.Causet { 481 switch ft.Tp { 482 case allegrosql.TypeLonglong: 483 return func(i int) types.Causet { return types.NewIntCauset(int64(i)) } 484 case allegrosql.TypeFloat: 485 return func(i int) types.Causet { return types.NewFloat32Causet(float32(i)) } 486 case allegrosql.TypeNewDecimal: 487 return func(i int) types.Causet { return types.NewDecimalCauset(types.NewDecFromInt(int64(i))) } 488 case allegrosql.TypeDouble: 489 return func(i int) types.Causet { return types.NewFloat64Causet(float64(i)) } 490 case allegrosql.TypeString: 491 return func(i int) types.Causet { return types.NewStringCauset(fmt.Sprintf("%d", i)) } 492 case allegrosql.TypeDate: 493 return func(i int) types.Causet { return types.NewTimeCauset(types.TimeFromDays(int64(i + 365))) } 494 case allegrosql.TypeDuration: 495 return func(i int) types.Causet { return types.NewDurationCauset(types.Duration{Duration: time.Duration(i)}) } 496 case allegrosql.TypeJSON: 497 return func(i int) types.Causet { return types.NewCauset(json.CreateBinary(int64(i))) } 498 case allegrosql.TypeEnum: 499 elems := []string{"a", "b", "c", "d", "e"} 500 return func(i int) types.Causet { 501 e, _ := types.ParseEnumValue(elems, uint64(i+1)) 502 return types.NewDefCauslateMysqlEnumCauset(e, ft.DefCauslate) 503 } 504 case allegrosql.TypeSet: 505 elems := []string{"a", "b", "c", "d", "e"} 506 return func(i int) types.Causet { 507 e, _ := types.ParseSetValue(elems, uint64(i+1)) 508 return types.NewMysqlSetCauset(e, ft.DefCauslate) 509 } 510 } 511 return nil 512 } 513 514 func (s *testSuite) testAggFunc(c *C, p aggTest) { 515 srcChk := p.genSrcChk() 516 517 args := []memex.Expression{&memex.DeferredCauset{RetType: p.dataType, Index: 0}} 518 if p.funcName == ast.AggFuncGroupConcat { 519 args = append(args, &memex.Constant{Value: types.NewStringCauset(" "), RetType: types.NewFieldType(allegrosql.TypeString)}) 520 } 521 desc, err := aggregation.NewAggFuncDesc(s.ctx, p.funcName, args, false) 522 c.Assert(err, IsNil) 523 if p.orderBy { 524 desc.OrderByItems = []*soliton.ByItems{ 525 {Expr: args[0], Desc: true}, 526 } 527 } 528 finalFunc := aggfuncs.Build(s.ctx, desc, 0) 529 finalPr, _ := finalFunc.AllocPartialResult() 530 resultChk := chunk.NewChunkWithCapacity([]*types.FieldType{desc.RetTp}, 1) 531 532 iter := chunk.NewIterator4Chunk(srcChk) 533 for event := iter.Begin(); event != iter.End(); event = iter.Next() { 534 finalFunc.UFIDelatePartialResult(s.ctx, []chunk.Event{event}, finalPr) 535 } 536 p.messUpChunk(srcChk) 537 finalFunc.AppendFinalResult2Chunk(s.ctx, finalPr, resultChk) 538 dt := resultChk.GetEvent(0).GetCauset(0, desc.RetTp) 539 result, err := dt.CompareCauset(s.ctx.GetStochastikVars().StmtCtx, &p.results[1]) 540 c.Assert(err, IsNil) 541 c.Assert(result, Equals, 0, Commentf("%v != %v", dt.String(), p.results[1])) 542 543 // test the empty input 544 resultChk.Reset() 545 finalFunc.ResetPartialResult(finalPr) 546 finalFunc.AppendFinalResult2Chunk(s.ctx, finalPr, resultChk) 547 dt = resultChk.GetEvent(0).GetCauset(0, desc.RetTp) 548 result, err = dt.CompareCauset(s.ctx.GetStochastikVars().StmtCtx, &p.results[0]) 549 c.Assert(err, IsNil) 550 c.Assert(result, Equals, 0, Commentf("%v != %v", dt.String(), p.results[0])) 551 552 // test the agg func with distinct 553 desc, err = aggregation.NewAggFuncDesc(s.ctx, p.funcName, args, true) 554 c.Assert(err, IsNil) 555 if p.orderBy { 556 desc.OrderByItems = []*soliton.ByItems{ 557 {Expr: args[0], Desc: true}, 558 } 559 } 560 finalFunc = aggfuncs.Build(s.ctx, desc, 0) 561 finalPr, _ = finalFunc.AllocPartialResult() 562 563 resultChk.Reset() 564 srcChk = p.genSrcChk() 565 iter = chunk.NewIterator4Chunk(srcChk) 566 for event := iter.Begin(); event != iter.End(); event = iter.Next() { 567 finalFunc.UFIDelatePartialResult(s.ctx, []chunk.Event{event}, finalPr) 568 } 569 p.messUpChunk(srcChk) 570 srcChk = p.genSrcChk() 571 iter = chunk.NewIterator4Chunk(srcChk) 572 for event := iter.Begin(); event != iter.End(); event = iter.Next() { 573 finalFunc.UFIDelatePartialResult(s.ctx, []chunk.Event{event}, finalPr) 574 } 575 p.messUpChunk(srcChk) 576 finalFunc.AppendFinalResult2Chunk(s.ctx, finalPr, resultChk) 577 dt = resultChk.GetEvent(0).GetCauset(0, desc.RetTp) 578 result, err = dt.CompareCauset(s.ctx.GetStochastikVars().StmtCtx, &p.results[1]) 579 c.Assert(err, IsNil) 580 c.Assert(result, Equals, 0, Commentf("%v != %v", dt.String(), p.results[1])) 581 582 // test the empty input 583 resultChk.Reset() 584 finalFunc.ResetPartialResult(finalPr) 585 finalFunc.AppendFinalResult2Chunk(s.ctx, finalPr, resultChk) 586 dt = resultChk.GetEvent(0).GetCauset(0, desc.RetTp) 587 result, err = dt.CompareCauset(s.ctx.GetStochastikVars().StmtCtx, &p.results[0]) 588 c.Assert(err, IsNil) 589 c.Assert(result, Equals, 0, Commentf("%v != %v", dt.String(), p.results[0])) 590 } 591 592 func (s *testSuite) testAggMemFunc(c *C, p aggMemTest) { 593 srcChk := p.aggTest.genSrcChk() 594 595 args := []memex.Expression{&memex.DeferredCauset{RetType: p.aggTest.dataType, Index: 0}} 596 if p.aggTest.funcName == ast.AggFuncGroupConcat { 597 args = append(args, &memex.Constant{Value: types.NewStringCauset(" "), RetType: types.NewFieldType(allegrosql.TypeString)}) 598 } 599 desc, err := aggregation.NewAggFuncDesc(s.ctx, p.aggTest.funcName, args, p.isDistinct) 600 c.Assert(err, IsNil) 601 if p.aggTest.orderBy { 602 desc.OrderByItems = []*soliton.ByItems{ 603 {Expr: args[0], Desc: true}, 604 } 605 } 606 finalFunc := aggfuncs.Build(s.ctx, desc, 0) 607 finalPr, memDelta := finalFunc.AllocPartialResult() 608 c.Assert(memDelta, Equals, p.allocMemDelta) 609 610 uFIDelateMemDeltas, err := p.uFIDelateMemDeltaGens(srcChk, p.aggTest.dataType) 611 c.Assert(err, IsNil) 612 iter := chunk.NewIterator4Chunk(srcChk) 613 i := 0 614 for event := iter.Begin(); event != iter.End(); event = iter.Next() { 615 memDelta, err := finalFunc.UFIDelatePartialResult(s.ctx, []chunk.Event{event}, finalPr) 616 c.Assert(err, IsNil) 617 c.Assert(memDelta, Equals, uFIDelateMemDeltas[i]) 618 i++ 619 } 620 } 621 622 func (s *testSuite) testMultiArgsAggFunc(c *C, p multiArgsAggTest) { 623 srcChk := p.genSrcChk() 624 625 args := make([]memex.Expression, len(p.dataTypes)) 626 for k := 0; k < len(p.dataTypes); k++ { 627 args[k] = &memex.DeferredCauset{RetType: p.dataTypes[k], Index: k} 628 } 629 if p.funcName == ast.AggFuncGroupConcat { 630 args = append(args, &memex.Constant{Value: types.NewStringCauset(" "), RetType: types.NewFieldType(allegrosql.TypeString)}) 631 } 632 633 desc, err := aggregation.NewAggFuncDesc(s.ctx, p.funcName, args, false) 634 c.Assert(err, IsNil) 635 if p.orderBy { 636 desc.OrderByItems = []*soliton.ByItems{ 637 {Expr: args[0], Desc: true}, 638 } 639 } 640 finalFunc := aggfuncs.Build(s.ctx, desc, 0) 641 finalPr, _ := finalFunc.AllocPartialResult() 642 resultChk := chunk.NewChunkWithCapacity([]*types.FieldType{desc.RetTp}, 1) 643 644 iter := chunk.NewIterator4Chunk(srcChk) 645 for event := iter.Begin(); event != iter.End(); event = iter.Next() { 646 finalFunc.UFIDelatePartialResult(s.ctx, []chunk.Event{event}, finalPr) 647 } 648 p.messUpChunk(srcChk) 649 finalFunc.AppendFinalResult2Chunk(s.ctx, finalPr, resultChk) 650 dt := resultChk.GetEvent(0).GetCauset(0, desc.RetTp) 651 result, err := dt.CompareCauset(s.ctx.GetStochastikVars().StmtCtx, &p.results[1]) 652 c.Assert(err, IsNil) 653 c.Assert(result, Equals, 0, Commentf("%v != %v", dt.String(), p.results[1])) 654 655 // test the empty input 656 resultChk.Reset() 657 finalFunc.ResetPartialResult(finalPr) 658 finalFunc.AppendFinalResult2Chunk(s.ctx, finalPr, resultChk) 659 dt = resultChk.GetEvent(0).GetCauset(0, desc.RetTp) 660 result, err = dt.CompareCauset(s.ctx.GetStochastikVars().StmtCtx, &p.results[0]) 661 c.Assert(err, IsNil) 662 c.Assert(result, Equals, 0, Commentf("%v != %v", dt.String(), p.results[0])) 663 664 // test the agg func with distinct 665 desc, err = aggregation.NewAggFuncDesc(s.ctx, p.funcName, args, true) 666 c.Assert(err, IsNil) 667 if p.orderBy { 668 desc.OrderByItems = []*soliton.ByItems{ 669 {Expr: args[0], Desc: true}, 670 } 671 } 672 finalFunc = aggfuncs.Build(s.ctx, desc, 0) 673 finalPr, _ = finalFunc.AllocPartialResult() 674 675 resultChk.Reset() 676 srcChk = p.genSrcChk() 677 iter = chunk.NewIterator4Chunk(srcChk) 678 for event := iter.Begin(); event != iter.End(); event = iter.Next() { 679 finalFunc.UFIDelatePartialResult(s.ctx, []chunk.Event{event}, finalPr) 680 } 681 p.messUpChunk(srcChk) 682 srcChk = p.genSrcChk() 683 iter = chunk.NewIterator4Chunk(srcChk) 684 for event := iter.Begin(); event != iter.End(); event = iter.Next() { 685 finalFunc.UFIDelatePartialResult(s.ctx, []chunk.Event{event}, finalPr) 686 } 687 p.messUpChunk(srcChk) 688 finalFunc.AppendFinalResult2Chunk(s.ctx, finalPr, resultChk) 689 dt = resultChk.GetEvent(0).GetCauset(0, desc.RetTp) 690 result, err = dt.CompareCauset(s.ctx.GetStochastikVars().StmtCtx, &p.results[1]) 691 c.Assert(err, IsNil) 692 c.Assert(result, Equals, 0, Commentf("%v != %v", dt.String(), p.results[1])) 693 694 // test the empty input 695 resultChk.Reset() 696 finalFunc.ResetPartialResult(finalPr) 697 finalFunc.AppendFinalResult2Chunk(s.ctx, finalPr, resultChk) 698 dt = resultChk.GetEvent(0).GetCauset(0, desc.RetTp) 699 result, err = dt.CompareCauset(s.ctx.GetStochastikVars().StmtCtx, &p.results[0]) 700 c.Assert(err, IsNil) 701 c.Assert(result, Equals, 0) 702 } 703 704 func (s *testSuite) benchmarkAggFunc(b *testing.B, p aggTest) { 705 srcChk := chunk.NewChunkWithCapacity([]*types.FieldType{p.dataType}, p.numEvents) 706 for i := 0; i < p.numEvents; i++ { 707 dt := p.dataGen(i) 708 srcChk.AppendCauset(0, &dt) 709 } 710 srcChk.AppendCauset(0, &types.Causet{}) 711 712 args := []memex.Expression{&memex.DeferredCauset{RetType: p.dataType, Index: 0}} 713 if p.funcName == ast.AggFuncGroupConcat { 714 args = append(args, &memex.Constant{Value: types.NewStringCauset(" "), RetType: types.NewFieldType(allegrosql.TypeString)}) 715 } 716 desc, err := aggregation.NewAggFuncDesc(s.ctx, p.funcName, args, false) 717 if err != nil { 718 b.Fatal(err) 719 } 720 if p.orderBy { 721 desc.OrderByItems = []*soliton.ByItems{ 722 {Expr: args[0], Desc: true}, 723 } 724 } 725 finalFunc := aggfuncs.Build(s.ctx, desc, 0) 726 resultChk := chunk.NewChunkWithCapacity([]*types.FieldType{desc.RetTp}, 1) 727 iter := chunk.NewIterator4Chunk(srcChk) 728 input := make([]chunk.Event, 0, iter.Len()) 729 for event := iter.Begin(); event != iter.End(); event = iter.Next() { 730 input = append(input, event) 731 } 732 b.Run(fmt.Sprintf("%v/%v", p.funcName, p.dataType), func(b *testing.B) { 733 s.baseBenchmarkAggFunc(b, finalFunc, input, resultChk) 734 }) 735 736 desc, err = aggregation.NewAggFuncDesc(s.ctx, p.funcName, args, true) 737 if err != nil { 738 b.Fatal(err) 739 } 740 if p.orderBy { 741 desc.OrderByItems = []*soliton.ByItems{ 742 {Expr: args[0], Desc: true}, 743 } 744 } 745 finalFunc = aggfuncs.Build(s.ctx, desc, 0) 746 resultChk.Reset() 747 b.Run(fmt.Sprintf("%v(distinct)/%v", p.funcName, p.dataType), func(b *testing.B) { 748 s.baseBenchmarkAggFunc(b, finalFunc, input, resultChk) 749 }) 750 } 751 752 func (s *testSuite) benchmarkMultiArgsAggFunc(b *testing.B, p multiArgsAggTest) { 753 srcChk := chunk.NewChunkWithCapacity(p.dataTypes, p.numEvents) 754 for i := 0; i < p.numEvents; i++ { 755 for j := 0; j < len(p.dataGens); j++ { 756 fdt := p.dataGens[j](i) 757 srcChk.AppendCauset(j, &fdt) 758 } 759 } 760 srcChk.AppendCauset(0, &types.Causet{}) 761 762 args := make([]memex.Expression, len(p.dataTypes)) 763 for k := 0; k < len(p.dataTypes); k++ { 764 args[k] = &memex.DeferredCauset{RetType: p.dataTypes[k], Index: k} 765 } 766 if p.funcName == ast.AggFuncGroupConcat { 767 args = append(args, &memex.Constant{Value: types.NewStringCauset(" "), RetType: types.NewFieldType(allegrosql.TypeString)}) 768 } 769 770 desc, err := aggregation.NewAggFuncDesc(s.ctx, p.funcName, args, false) 771 if err != nil { 772 b.Fatal(err) 773 } 774 if p.orderBy { 775 desc.OrderByItems = []*soliton.ByItems{ 776 {Expr: args[0], Desc: true}, 777 } 778 } 779 finalFunc := aggfuncs.Build(s.ctx, desc, 0) 780 resultChk := chunk.NewChunkWithCapacity([]*types.FieldType{desc.RetTp}, 1) 781 iter := chunk.NewIterator4Chunk(srcChk) 782 input := make([]chunk.Event, 0, iter.Len()) 783 for event := iter.Begin(); event != iter.End(); event = iter.Next() { 784 input = append(input, event) 785 } 786 b.Run(fmt.Sprintf("%v/%v", p.funcName, p.dataTypes), func(b *testing.B) { 787 s.baseBenchmarkAggFunc(b, finalFunc, input, resultChk) 788 }) 789 790 desc, err = aggregation.NewAggFuncDesc(s.ctx, p.funcName, args, true) 791 if err != nil { 792 b.Fatal(err) 793 } 794 if p.orderBy { 795 desc.OrderByItems = []*soliton.ByItems{ 796 {Expr: args[0], Desc: true}, 797 } 798 } 799 finalFunc = aggfuncs.Build(s.ctx, desc, 0) 800 resultChk.Reset() 801 b.Run(fmt.Sprintf("%v(distinct)/%v", p.funcName, p.dataTypes), func(b *testing.B) { 802 s.baseBenchmarkAggFunc(b, finalFunc, input, resultChk) 803 }) 804 } 805 806 func (s *testSuite) baseBenchmarkAggFunc(b *testing.B, 807 finalFunc aggfuncs.AggFunc, input []chunk.Event, output *chunk.Chunk) { 808 finalPr, _ := finalFunc.AllocPartialResult() 809 output.Reset() 810 b.ResetTimer() 811 for i := 0; i < b.N; i++ { 812 finalFunc.UFIDelatePartialResult(s.ctx, input, finalPr) 813 b.StopTimer() 814 output.Reset() 815 b.StartTimer() 816 } 817 }