github.com/matrixorigin/matrixone@v0.7.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 "testing" 20 21 "github.com/matrixorigin/matrixone/pkg/common/mpool" 22 "github.com/matrixorigin/matrixone/pkg/sql/colexec/agg" 23 24 "github.com/matrixorigin/matrixone/pkg/container/batch" 25 "github.com/matrixorigin/matrixone/pkg/container/index" 26 "github.com/matrixorigin/matrixone/pkg/container/types" 27 "github.com/matrixorigin/matrixone/pkg/container/vector" 28 "github.com/matrixorigin/matrixone/pkg/pb/plan" 29 "github.com/matrixorigin/matrixone/pkg/testutil" 30 "github.com/matrixorigin/matrixone/pkg/vm/process" 31 "github.com/stretchr/testify/require" 32 ) 33 34 const ( 35 Rows = 10 // default rows 36 BenchmarkRows = 100000 // default rows for benchmark 37 ) 38 39 // add unit tests for cases 40 type groupTestCase struct { 41 arg *Argument 42 flgs []bool // flgs[i] == true: nullable 43 types []types.Type 44 proc *process.Process 45 } 46 47 var ( 48 tcs []groupTestCase 49 ) 50 51 func init() { 52 tcs = []groupTestCase{ 53 newTestCase([]bool{false}, []types.Type{{Oid: types.T_int8}}, []*plan.Expr{}, []agg.Aggregate{{Op: 0, E: newExpression(0)}}), 54 newTestCase([]bool{false}, []types.Type{{Oid: types.T_int8}}, []*plan.Expr{newExpression(0)}, []agg.Aggregate{{Op: 0, E: newExpression(0)}}), 55 newTestCase([]bool{false, true, false, true}, []types.Type{ 56 {Oid: types.T_int8}, 57 {Oid: types.T_int16}, 58 }, []*plan.Expr{newExpression(0), newExpression(1)}, []agg.Aggregate{{Op: 0, E: newExpression(0)}}), 59 newTestCase([]bool{false, true, false, true}, []types.Type{ 60 {Oid: types.T_int8}, 61 {Oid: types.T_int16}, 62 {Oid: types.T_int32}, 63 {Oid: types.T_int64}, 64 }, []*plan.Expr{newExpression(0), newExpression(3)}, []agg.Aggregate{{Op: 0, E: newExpression(0)}}), 65 newTestCase([]bool{false, true, false, true}, []types.Type{ 66 {Oid: types.T_int64}, 67 {Oid: types.T_int64}, 68 {Oid: types.T_int64}, 69 {Oid: types.T_decimal128}, 70 }, []*plan.Expr{newExpression(1), newExpression(3)}, []agg.Aggregate{{Op: 0, E: newExpression(0)}}), 71 newTestCase([]bool{false, true, false, true}, []types.Type{ 72 {Oid: types.T_int64}, 73 {Oid: types.T_int64}, 74 {Oid: types.T_int64}, 75 {Oid: types.T_decimal128}, 76 }, []*plan.Expr{newExpression(1), newExpression(2), newExpression(3)}, []agg.Aggregate{{Op: 0, E: newExpression(0)}}), 77 newTestCase([]bool{false, true, false, true}, []types.Type{ 78 {Oid: types.T_int64}, 79 {Oid: types.T_int64}, 80 {Oid: types.T_varchar, Width: 2}, 81 {Oid: types.T_decimal128}, 82 }, []*plan.Expr{newExpression(1), newExpression(2), newExpression(3)}, []agg.Aggregate{{Op: 0, E: newExpression(0)}}), 83 newTestCase([]bool{false, true, false, true}, []types.Type{ 84 {Oid: types.T_int64}, 85 {Oid: types.T_int64}, 86 {Oid: types.T_varchar, Width: types.MaxVarcharLen}, 87 {Oid: types.T_decimal128}, 88 }, []*plan.Expr{newExpression(1), newExpression(2), newExpression(3)}, []agg.Aggregate{{Op: 0, E: newExpression(0)}}), 89 } 90 } 91 92 func TestString(t *testing.T) { 93 buf := new(bytes.Buffer) 94 for _, tc := range tcs { 95 String(tc.arg, buf) 96 } 97 } 98 99 func TestGroup(t *testing.T) { 100 for _, tc := range tcs { 101 err := Prepare(tc.proc, tc.arg) 102 require.NoError(t, err) 103 tc.proc.Reg.InputBatch = newBatch(t, tc.flgs, tc.types, tc.proc, Rows) 104 _, err = Call(0, tc.proc, tc.arg, false, false) 105 require.NoError(t, err) 106 tc.proc.Reg.InputBatch = newBatch(t, tc.flgs, tc.types, tc.proc, Rows) 107 _, err = Call(0, tc.proc, tc.arg, false, false) 108 require.NoError(t, err) 109 tc.proc.Reg.InputBatch = &batch.Batch{} 110 _, err = Call(0, tc.proc, tc.arg, false, false) 111 require.NoError(t, err) 112 tc.proc.Reg.InputBatch = nil 113 _, err = Call(0, tc.proc, tc.arg, false, false) 114 require.NoError(t, err) 115 if tc.proc.Reg.InputBatch != nil { 116 tc.proc.Reg.InputBatch.Clean(tc.proc.Mp()) 117 } 118 tc.proc.Reg.InputBatch = nil 119 _, err = Call(0, tc.proc, tc.arg, false, false) 120 require.NoError(t, err) 121 tc.arg.Free(tc.proc, false) 122 require.Equal(t, int64(0), tc.proc.Mp().CurrNB()) 123 } 124 } 125 126 func TestLowCardinalityGroup(t *testing.T) { 127 { 128 // SELECT COUNT(*) FROM t GROUP BY t.values 129 tc := newTestCase([]bool{false}, []types.Type{{Oid: types.T_varchar}}, 130 []*plan.Expr{newExpression(0)}, []agg.Aggregate{{Op: 5, E: newExpression(0)}}) 131 tc.arg.NeedEval = true 132 133 // a->4, b->3, c->3, d->2 134 values := []string{"a", "b", "b", "a", "c", "b", "c", "a", "a", "d", "c", "d"} 135 v := testutil.NewVector(len(values), types.T_varchar.ToType(), tc.proc.Mp(), false, values) 136 constructIndex(t, v, tc.proc.Mp()) 137 138 err := Prepare(tc.proc, tc.arg) 139 require.NoError(t, err) 140 tc.proc.Reg.InputBatch = testutil.NewBatchWithVectors([]*vector.Vector{v}, nil) 141 _, err = Call(0, tc.proc, tc.arg, false, false) 142 require.NoError(t, err) 143 tc.proc.Reg.InputBatch = nil 144 _, err = Call(0, tc.proc, tc.arg, false, false) 145 require.NoError(t, err) 146 147 rbat := tc.proc.Reg.InputBatch 148 require.Equal(t, []string{"a", "b", "c", "d"}, vector.GetStrVectorValues(rbat.Vecs[0])) 149 require.Equal(t, []int64{4, 3, 3, 2}, vector.MustTCols[int64](rbat.Vecs[1])) 150 151 if tc.proc.Reg.InputBatch != nil { 152 tc.proc.Reg.InputBatch.Clean(tc.proc.Mp()) 153 } 154 } 155 156 { 157 // SELECT SUM(t.values) FROM t GROUP BY t.values 158 tc := newTestCase([]bool{false}, []types.Type{{Oid: types.T_int64}}, 159 []*plan.Expr{newExpression(0)}, []agg.Aggregate{{Op: 0, E: newExpression(0)}}) 160 tc.arg.NeedEval = true 161 162 // 16->32, 1->2, 4->8, 2->6, 8->16, 32->32 163 values := []int64{16, 16, 1, 4, 4, 2, 8, 8, 1, 32, 2, 2} 164 v := testutil.NewVector(len(values), types.T_int64.ToType(), tc.proc.Mp(), false, values) 165 constructIndex(t, v, tc.proc.Mp()) 166 167 err := Prepare(tc.proc, tc.arg) 168 require.NoError(t, err) 169 tc.proc.Reg.InputBatch = testutil.NewBatchWithVectors([]*vector.Vector{v}, nil) 170 _, err = Call(0, tc.proc, tc.arg, false, false) 171 require.NoError(t, err) 172 tc.proc.Reg.InputBatch = nil 173 _, err = Call(0, tc.proc, tc.arg, false, false) 174 require.NoError(t, err) 175 176 rbat := tc.proc.Reg.InputBatch 177 require.Equal(t, []int64{16, 1, 4, 2, 8, 32}, vector.MustTCols[int64](rbat.Vecs[0])) 178 require.Equal(t, []int64{32, 2, 8, 6, 16, 32}, vector.MustTCols[int64](rbat.Vecs[1])) 179 180 if tc.proc.Reg.InputBatch != nil { 181 tc.proc.Reg.InputBatch.Clean(tc.proc.Mp()) 182 } 183 } 184 } 185 186 func BenchmarkGroup(b *testing.B) { 187 for i := 0; i < b.N; i++ { 188 tcs = []groupTestCase{ 189 newTestCase([]bool{false}, []types.Type{{Oid: types.T_int8}}, []*plan.Expr{}, []agg.Aggregate{{Op: 0, E: newExpression(0)}}), 190 newTestCase([]bool{false}, []types.Type{{Oid: types.T_int8}}, []*plan.Expr{newExpression(0)}, []agg.Aggregate{{Op: 0, E: newExpression(0)}}), 191 } 192 t := new(testing.T) 193 for _, tc := range tcs { 194 err := Prepare(tc.proc, tc.arg) 195 require.NoError(t, err) 196 tc.proc.Reg.InputBatch = newBatch(t, tc.flgs, tc.types, tc.proc, BenchmarkRows) 197 _, err = Call(0, tc.proc, tc.arg, false, false) 198 require.NoError(t, err) 199 tc.proc.Reg.InputBatch = newBatch(t, tc.flgs, tc.types, tc.proc, BenchmarkRows) 200 _, err = Call(0, tc.proc, tc.arg, false, false) 201 require.NoError(t, err) 202 tc.proc.Reg.InputBatch = &batch.Batch{} 203 _, err = Call(0, tc.proc, tc.arg, false, false) 204 require.NoError(t, err) 205 tc.proc.Reg.InputBatch = nil 206 _, err = Call(0, tc.proc, tc.arg, false, false) 207 require.NoError(t, err) 208 if tc.proc.Reg.InputBatch != nil { 209 tc.proc.Reg.InputBatch.Clean(tc.proc.Mp()) 210 } 211 } 212 } 213 } 214 215 func newTestCase(flgs []bool, ts []types.Type, exprs []*plan.Expr, aggs []agg.Aggregate) groupTestCase { 216 return groupTestCase{ 217 types: ts, 218 flgs: flgs, 219 proc: testutil.NewProcessWithMPool(mpool.MustNewZero()), 220 arg: &Argument{ 221 Aggs: aggs, 222 Exprs: exprs, 223 }, 224 } 225 } 226 227 func newExpression(pos int32) *plan.Expr { 228 return &plan.Expr{ 229 Typ: new(plan.Type), 230 Expr: &plan.Expr_Col{ 231 Col: &plan.ColRef{ 232 ColPos: pos, 233 }, 234 }, 235 } 236 } 237 238 // create a new block based on the type information, flgs[i] == ture: has null 239 func newBatch(t *testing.T, flgs []bool, ts []types.Type, proc *process.Process, rows int64) *batch.Batch { 240 return testutil.NewBatch(ts, false, int(rows), proc.Mp()) 241 } 242 243 func constructIndex(t *testing.T, v *vector.Vector, m *mpool.MPool) { 244 idx, err := index.New(v.Typ, m) 245 require.NoError(t, err) 246 247 err = idx.InsertBatch(v) 248 require.NoError(t, err) 249 250 v.SetIndex(idx) 251 }