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  }