github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/colexec/semi/join_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 semi 16 17 import ( 18 "bytes" 19 "context" 20 "testing" 21 22 "github.com/matrixorigin/matrixone/pkg/common/hashmap" 23 "github.com/matrixorigin/matrixone/pkg/common/mpool" 24 "github.com/matrixorigin/matrixone/pkg/container/batch" 25 "github.com/matrixorigin/matrixone/pkg/container/types" 26 "github.com/matrixorigin/matrixone/pkg/pb/plan" 27 "github.com/matrixorigin/matrixone/pkg/sql/colexec/hashbuild" 28 "github.com/matrixorigin/matrixone/pkg/sql/plan/function" 29 "github.com/matrixorigin/matrixone/pkg/testutil" 30 "github.com/matrixorigin/matrixone/pkg/vm" 31 "github.com/matrixorigin/matrixone/pkg/vm/process" 32 "github.com/stretchr/testify/require" 33 ) 34 35 const ( 36 Rows = 10 // default rows 37 BenchmarkRows = 100000 // default rows for benchmark 38 ) 39 40 // add unit tests for cases 41 type joinTestCase struct { 42 arg *Argument 43 flgs []bool // flgs[i] == true: nullable 44 types []types.Type 45 proc *process.Process 46 cancel context.CancelFunc 47 barg *hashbuild.Argument 48 } 49 50 var ( 51 tcs []joinTestCase 52 ) 53 54 func init() { 55 tcs = []joinTestCase{ 56 newTestCase(mpool.MustNewZero(), []bool{false}, []types.Type{types.T_int8.ToType()}, []int32{0}, 57 [][]*plan.Expr{ 58 { 59 newExpr(0, types.T_int8.ToType()), 60 }, 61 { 62 newExpr(0, types.T_int8.ToType()), 63 }, 64 }), 65 newTestCase(mpool.MustNewZero(), []bool{true}, []types.Type{types.T_int8.ToType()}, []int32{0}, 66 [][]*plan.Expr{ 67 { 68 newExpr(0, types.T_int8.ToType()), 69 }, 70 { 71 newExpr(0, types.T_int8.ToType()), 72 }, 73 }), 74 } 75 } 76 77 func TestString(t *testing.T) { 78 buf := new(bytes.Buffer) 79 for _, tc := range tcs { 80 tc.arg.String(buf) 81 } 82 } 83 84 func TestJoin(t *testing.T) { 85 for _, tc := range tcs { 86 bats := hashBuild(t, tc) 87 if jm, ok := bats[0].AuxData.(*hashmap.JoinMap); ok { 88 jm.SetDupCount(int64(1)) 89 } 90 err := tc.arg.Prepare(tc.proc) 91 require.NoError(t, err) 92 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 93 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 94 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 95 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 96 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 97 tc.proc.Reg.MergeReceivers[0].Ch <- nil 98 tc.proc.Reg.MergeReceivers[1].Ch <- bats[0] 99 tc.proc.Reg.MergeReceivers[1].Ch <- bats[1] 100 tc.proc.Reg.MergeReceivers[0].Ch <- nil 101 tc.proc.Reg.MergeReceivers[1].Ch <- nil 102 for { 103 ok, err := tc.arg.Call(tc.proc) 104 if ok.Status == vm.ExecStop || err != nil { 105 break 106 } 107 } 108 tc.arg.Free(tc.proc, false, nil) 109 tc.proc.FreeVectors() 110 require.Equal(t, int64(0), tc.proc.Mp().CurrNB()) 111 } 112 } 113 114 func BenchmarkJoin(b *testing.B) { 115 for i := 0; i < b.N; i++ { 116 tcs = []joinTestCase{ 117 newTestCase(mpool.MustNewZero(), []bool{false}, []types.Type{types.T_int8.ToType()}, []int32{0}, 118 [][]*plan.Expr{ 119 { 120 newExpr(0, types.T_int8.ToType()), 121 }, 122 { 123 newExpr(0, types.T_int8.ToType()), 124 }, 125 }), 126 newTestCase(mpool.MustNewZero(), []bool{true}, []types.Type{types.T_int8.ToType()}, []int32{0}, 127 [][]*plan.Expr{ 128 { 129 newExpr(0, types.T_int8.ToType()), 130 }, 131 { 132 newExpr(0, types.T_int8.ToType()), 133 }, 134 }), 135 } 136 t := new(testing.T) 137 for _, tc := range tcs { 138 bats := hashBuild(t, tc) 139 err := tc.arg.Prepare(tc.proc) 140 require.NoError(t, err) 141 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 142 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 143 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 144 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 145 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 146 tc.proc.Reg.MergeReceivers[0].Ch <- nil 147 tc.proc.Reg.MergeReceivers[1].Ch <- bats[0] 148 tc.proc.Reg.MergeReceivers[1].Ch <- bats[1] 149 for { 150 ok, err := tc.arg.Call(tc.proc) 151 if ok.Status == vm.ExecStop || err != nil { 152 break 153 } 154 } 155 } 156 } 157 } 158 159 func newExpr(pos int32, typ types.Type) *plan.Expr { 160 return &plan.Expr{ 161 Typ: plan.Type{ 162 Scale: typ.Scale, 163 Width: typ.Width, 164 Id: int32(typ.Oid), 165 }, 166 Expr: &plan.Expr_Col{ 167 Col: &plan.ColRef{ 168 ColPos: pos, 169 }, 170 }, 171 } 172 } 173 174 func newTestCase(m *mpool.MPool, flgs []bool, ts []types.Type, rp []int32, cs [][]*plan.Expr) joinTestCase { 175 proc := testutil.NewProcessWithMPool(m) 176 proc.Reg.MergeReceivers = make([]*process.WaitRegister, 2) 177 ctx, cancel := context.WithCancel(context.Background()) 178 proc.Reg.MergeReceivers[0] = &process.WaitRegister{ 179 Ctx: ctx, 180 Ch: make(chan *batch.Batch, 10), 181 } 182 proc.Reg.MergeReceivers[1] = &process.WaitRegister{ 183 Ctx: ctx, 184 Ch: make(chan *batch.Batch, 10), 185 } 186 fr, _ := function.GetFunctionByName(ctx, "=", ts) 187 fid := fr.GetEncodedOverloadID() 188 args := make([]*plan.Expr, 0, 2) 189 args = append(args, &plan.Expr{ 190 Typ: plan.Type{ 191 Id: int32(ts[0].Oid), 192 }, 193 Expr: &plan.Expr_Col{ 194 Col: &plan.ColRef{ 195 RelPos: 0, 196 ColPos: 0, 197 }, 198 }, 199 }) 200 args = append(args, &plan.Expr{ 201 Typ: plan.Type{ 202 Id: int32(ts[0].Oid), 203 }, 204 Expr: &plan.Expr_Col{ 205 Col: &plan.ColRef{ 206 RelPos: 1, 207 ColPos: 0, 208 }, 209 }, 210 }) 211 cond := &plan.Expr{ 212 Typ: plan.Type{ 213 Id: int32(types.T_bool), 214 }, 215 Expr: &plan.Expr_F{ 216 F: &plan.Function{ 217 Args: args, 218 Func: &plan.ObjectRef{Obj: fid, ObjName: "="}, 219 }, 220 }, 221 } 222 return joinTestCase{ 223 types: ts, 224 flgs: flgs, 225 proc: proc, 226 cancel: cancel, 227 arg: &Argument{ 228 Typs: ts, 229 Result: rp, 230 Conditions: cs, 231 Cond: cond, 232 OperatorBase: vm.OperatorBase{ 233 OperatorInfo: vm.OperatorInfo{ 234 Idx: 0, 235 IsFirst: false, 236 IsLast: false, 237 }, 238 }, 239 }, 240 barg: &hashbuild.Argument{ 241 Typs: ts, 242 NeedHashMap: true, 243 Conditions: cs[1], 244 OperatorBase: vm.OperatorBase{ 245 OperatorInfo: vm.OperatorInfo{ 246 Idx: 0, 247 IsFirst: false, 248 IsLast: false, 249 }, 250 }, 251 NeedAllocateSels: true, 252 NeedMergedBatch: true, 253 }, 254 } 255 } 256 257 func hashBuild(t *testing.T, tc joinTestCase) []*batch.Batch { 258 err := tc.barg.Prepare(tc.proc) 259 require.NoError(t, err) 260 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 261 for _, r := range tc.proc.Reg.MergeReceivers { 262 r.Ch <- nil 263 } 264 ok1, err := tc.barg.Call(tc.proc) 265 require.NoError(t, err) 266 require.Equal(t, false, ok1.Status == vm.ExecStop) 267 ok2, err := tc.barg.Call(tc.proc) 268 require.NoError(t, err) 269 require.Equal(t, false, ok2.Status == vm.ExecStop) 270 return []*batch.Batch{ok1.Batch, ok2.Batch} 271 } 272 273 // create a new block based on the type information, flgs[i] == ture: has null 274 func newBatch(ts []types.Type, proc *process.Process, rows int64) *batch.Batch { 275 return testutil.NewBatch(ts, false, int(rows), proc.Mp()) 276 }