github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/colexec/group/group_test.go (about)

     1  // Copyright 2021 Matrix Origin
     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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package group
    16  
    17  import (
    18  	"bytes"
    19  	"github.com/matrixorigin/matrixone/pkg/sql/colexec/aggexec"
    20  	"testing"
    21  
    22  	"github.com/matrixorigin/matrixone/pkg/sql/plan/function"
    23  
    24  	"github.com/matrixorigin/matrixone/pkg/common/mpool"
    25  	"github.com/matrixorigin/matrixone/pkg/sql/colexec/value_scan"
    26  	"github.com/matrixorigin/matrixone/pkg/vm"
    27  
    28  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    29  	"github.com/matrixorigin/matrixone/pkg/container/types"
    30  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    31  	"github.com/matrixorigin/matrixone/pkg/testutil"
    32  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    33  	"github.com/stretchr/testify/require"
    34  )
    35  
    36  const (
    37  	Rows          = 10     // default rows
    38  	BenchmarkRows = 100000 // default rows for benchmark
    39  )
    40  
    41  // add unit tests for cases
    42  type groupTestCase struct {
    43  	arg  *Argument
    44  	flgs []bool // flgs[i] == true: nullable
    45  	proc *process.Process
    46  }
    47  
    48  var (
    49  	tcs []groupTestCase
    50  )
    51  
    52  func init() {
    53  	tcs = []groupTestCase{
    54  		newTestCase([]bool{false}, []types.Type{types.T_int8.ToType()}, nil, 0),
    55  		newTestCase([]bool{false}, []types.Type{types.T_int8.ToType()}, []int{0}, 0),
    56  		newTestCase([]bool{false, true, false, true}, []types.Type{
    57  			types.T_int8.ToType(),
    58  			types.T_int16.ToType(),
    59  		}, []int{0, 1}, 0),
    60  		newTestCase([]bool{false, true, false, true}, []types.Type{
    61  			types.T_int8.ToType(),
    62  			types.T_int16.ToType(),
    63  			types.T_int32.ToType(),
    64  			types.T_int64.ToType(),
    65  		}, []int{0, 3}, 0),
    66  		newTestCase([]bool{false, true, false, true}, []types.Type{
    67  			types.T_int64.ToType(),
    68  			types.T_int64.ToType(),
    69  			types.T_int64.ToType(),
    70  			types.T_decimal128.ToType(),
    71  		}, []int{1, 3}, 0),
    72  		newTestCase([]bool{false, true, false, true}, []types.Type{
    73  			types.T_int64.ToType(),
    74  			types.T_int64.ToType(),
    75  			types.T_int64.ToType(),
    76  			types.T_decimal128.ToType(),
    77  		}, []int{1, 2, 3}, 0),
    78  		newTestCase([]bool{false, true, false, true}, []types.Type{
    79  			types.T_int64.ToType(),
    80  			types.T_int64.ToType(),
    81  			types.New(types.T_varchar, 2, 0),
    82  			types.T_decimal128.ToType(),
    83  		}, []int{1, 2, 3}, 0),
    84  		newTestCase([]bool{false, true, false, true}, []types.Type{
    85  			types.T_int64.ToType(),
    86  			types.T_int64.ToType(),
    87  			types.T_varchar.ToType(),
    88  			types.T_decimal128.ToType(),
    89  		}, []int{1, 2, 3}, 0),
    90  	}
    91  }
    92  
    93  func TestString(t *testing.T) {
    94  	buf := new(bytes.Buffer)
    95  	for _, tc := range tcs {
    96  		tc.arg.String(buf)
    97  	}
    98  }
    99  
   100  func TestGroup(t *testing.T) {
   101  	for _, tc := range tcs {
   102  		err := tc.arg.Prepare(tc.proc)
   103  		require.NoError(t, err)
   104  
   105  		bats := []*batch.Batch{
   106  			newBatch(tc.arg.Types, tc.proc, Rows),
   107  			newBatch(tc.arg.Types, tc.proc, Rows),
   108  			batch.EmptyBatch,
   109  		}
   110  		resetChildren(tc.arg, bats)
   111  		_, err = tc.arg.Call(tc.proc)
   112  		require.NoError(t, err)
   113  
   114  		tc.arg.Free(tc.proc, false, nil)
   115  		tc.arg.GetChildren(0).Free(tc.proc, false, nil)
   116  		tc.proc.FreeVectors()
   117  		require.Equal(t, int64(0), tc.proc.Mp().CurrNB())
   118  	}
   119  }
   120  
   121  func BenchmarkGroup(b *testing.B) {
   122  	for i := 0; i < b.N; i++ {
   123  		tcs = []groupTestCase{
   124  			newTestCase([]bool{false}, []types.Type{types.T_int8.ToType()}, nil, 0),
   125  			newTestCase([]bool{false}, []types.Type{types.T_int8.ToType()}, []int{0}, 0),
   126  		}
   127  		t := new(testing.T)
   128  		for _, tc := range tcs {
   129  			err := tc.arg.Prepare(tc.proc)
   130  			require.NoError(t, err)
   131  			bats := []*batch.Batch{
   132  				newBatch(tc.arg.Types, tc.proc, BenchmarkRows),
   133  				newBatch(tc.arg.Types, tc.proc, BenchmarkRows),
   134  				batch.EmptyBatch,
   135  			}
   136  			resetChildren(tc.arg, bats)
   137  			_, err = tc.arg.Call(tc.proc)
   138  			require.NoError(t, err)
   139  
   140  			tc.arg.Free(tc.proc, false, nil)
   141  			tc.arg.GetChildren(0).Free(tc.proc, false, nil)
   142  			tc.proc.FreeVectors()
   143  		}
   144  	}
   145  }
   146  
   147  func newTestCase(flgs []bool, ts []types.Type, exprIdx []int, pos int32) groupTestCase {
   148  	exprs := []*plan.Expr{}
   149  	for _, idx := range exprIdx {
   150  		exprs = append(exprs, newExpression(int32(idx), ts))
   151  	}
   152  	aggs := []aggexec.AggFuncExecExpression{
   153  		aggexec.MakeAggFunctionExpression(function.AggSumOverloadID, false, []*plan.Expr{newExpression(pos, ts)}, nil)}
   154  
   155  	for _, expr := range exprs {
   156  		if col, ok := expr.Expr.(*plan.Expr_Col); ok {
   157  			idx := col.Col.ColPos
   158  			expr.Typ = plan.Type{
   159  				Id:    int32(ts[idx].Oid),
   160  				Width: ts[idx].Width,
   161  				Scale: ts[idx].Scale,
   162  			}
   163  		}
   164  	}
   165  	return groupTestCase{
   166  		flgs: flgs,
   167  		proc: testutil.NewProcessWithMPool(mpool.MustNewZero()),
   168  		arg: &Argument{
   169  			Exprs: exprs,
   170  			Types: ts,
   171  			Aggs:  aggs,
   172  			OperatorBase: vm.OperatorBase{
   173  				OperatorInfo: vm.OperatorInfo{
   174  					Idx:     1,
   175  					IsFirst: false,
   176  					IsLast:  false,
   177  				},
   178  			},
   179  		},
   180  	}
   181  }
   182  
   183  func newExpression(pos int32, typs []types.Type) *plan.Expr {
   184  	return &plan.Expr{
   185  		Typ: plan.Type{Id: int32(typs[pos].Oid)},
   186  		Expr: &plan.Expr_Col{
   187  			Col: &plan.ColRef{
   188  				ColPos: pos,
   189  			},
   190  		},
   191  	}
   192  }
   193  
   194  // create a new block based on the type information, flgs[i] == ture: has null
   195  func newBatch(ts []types.Type, proc *process.Process, rows int64) *batch.Batch {
   196  	return testutil.NewBatch(ts, false, int(rows), proc.Mp())
   197  }
   198  
   199  func resetChildren(arg *Argument, bats []*batch.Batch) {
   200  	if arg.NumChildren() == 0 {
   201  		arg.AppendChild(&value_scan.Argument{
   202  			Batchs: bats,
   203  		})
   204  
   205  	} else {
   206  		arg.SetChildren(
   207  			[]vm.Operator{
   208  				&value_scan.Argument{
   209  					Batchs: bats,
   210  				},
   211  			})
   212  	}
   213  	arg.ctr.state = vm.Build
   214  }