github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/colexec/rightsemi/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 rightsemi 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([]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([]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 nb0 := tc.proc.Mp().CurrNB() 87 bats := hashBuild(t, tc) 88 if jm, ok := bats[0].AuxData.(*hashmap.JoinMap); ok { 89 jm.SetDupCount(int64(1)) 90 } 91 err := tc.arg.Prepare(tc.proc) 92 require.NoError(t, err) 93 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 94 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 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 <- newBatch(tc.types, tc.proc, Rows) 98 tc.proc.Reg.MergeReceivers[0].Ch <- nil 99 tc.proc.Reg.MergeReceivers[1].Ch <- bats[0] 100 tc.proc.Reg.MergeReceivers[1].Ch <- bats[1] 101 tc.proc.Reg.MergeReceivers[0].Ch <- nil 102 tc.proc.Reg.MergeReceivers[1].Ch <- nil 103 for { 104 ok, err := tc.arg.Call(tc.proc) 105 if ok.Status == vm.ExecStop || err != nil { 106 break 107 } 108 } 109 tc.arg.Free(tc.proc, false, nil) 110 tc.proc.FreeVectors() 111 nb1 := tc.proc.Mp().CurrNB() 112 require.Equal(t, nb0, nb1) 113 } 114 115 for _, tc := range tcs { 116 nb0 := tc.proc.Mp().CurrNB() 117 err := tc.arg.Prepare(tc.proc) 118 require.NoError(t, err) 119 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 120 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 121 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 122 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 123 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 124 tc.proc.Reg.MergeReceivers[0].Ch <- nil 125 tc.proc.Reg.MergeReceivers[1].Ch <- nil 126 tc.proc.Reg.MergeReceivers[0].Ch <- nil 127 tc.proc.Reg.MergeReceivers[1].Ch <- nil 128 for { 129 ok, err := tc.arg.Call(tc.proc) 130 if ok.Status == vm.ExecStop || err != nil { 131 break 132 } 133 } 134 tc.proc.FreeVectors() 135 tc.arg.Free(tc.proc, false, nil) 136 nb1 := tc.proc.Mp().CurrNB() 137 require.Equal(t, nb0, nb1) 138 } 139 } 140 141 func BenchmarkJoin(b *testing.B) { 142 for i := 0; i < b.N; i++ { 143 tcs = []joinTestCase{ 144 newTestCase([]bool{false}, []types.Type{types.T_int8.ToType()}, []int32{0}, 145 [][]*plan.Expr{ 146 { 147 newExpr(0, types.T_int8.ToType()), 148 }, 149 { 150 newExpr(0, types.T_int8.ToType()), 151 }, 152 }), 153 newTestCase([]bool{true}, []types.Type{types.T_int8.ToType()}, []int32{0}, 154 [][]*plan.Expr{ 155 { 156 newExpr(0, types.T_int8.ToType()), 157 }, 158 { 159 newExpr(0, types.T_int8.ToType()), 160 }, 161 }), 162 } 163 t := new(testing.T) 164 for _, tc := range tcs { 165 bats := hashBuild(t, tc) 166 err := tc.arg.Prepare(tc.proc) 167 require.NoError(t, err) 168 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 169 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 170 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 171 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 172 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 173 tc.proc.Reg.MergeReceivers[0].Ch <- nil 174 tc.proc.Reg.MergeReceivers[1].Ch <- bats[0] 175 tc.proc.Reg.MergeReceivers[1].Ch <- bats[1] 176 for { 177 ok, err := tc.arg.Call(tc.proc) 178 if ok.Status == vm.ExecStop || err != nil { 179 break 180 } 181 } 182 } 183 } 184 } 185 186 func newExpr(pos int32, typ types.Type) *plan.Expr { 187 return &plan.Expr{ 188 Typ: plan.Type{ 189 Scale: typ.Scale, 190 Width: typ.Width, 191 Id: int32(typ.Oid), 192 }, 193 Expr: &plan.Expr_Col{ 194 Col: &plan.ColRef{ 195 ColPos: pos, 196 }, 197 }, 198 } 199 } 200 201 func newTestCase(flgs []bool, ts []types.Type, rp []int32, cs [][]*plan.Expr) joinTestCase { 202 proc := testutil.NewProcessWithMPool(mpool.MustNewZero()) 203 proc.Reg.MergeReceivers = make([]*process.WaitRegister, 2) 204 ctx, cancel := context.WithCancel(context.Background()) 205 proc.Reg.MergeReceivers[0] = &process.WaitRegister{ 206 Ctx: ctx, 207 Ch: make(chan *batch.Batch, 10), 208 } 209 proc.Reg.MergeReceivers[1] = &process.WaitRegister{ 210 Ctx: ctx, 211 Ch: make(chan *batch.Batch, 10), 212 } 213 fr, _ := function.GetFunctionByName(ctx, "=", ts) 214 fid := fr.GetEncodedOverloadID() 215 args := make([]*plan.Expr, 0, 2) 216 args = append(args, &plan.Expr{ 217 Typ: plan.Type{ 218 Id: int32(ts[0].Oid), 219 }, 220 Expr: &plan.Expr_Col{ 221 Col: &plan.ColRef{ 222 RelPos: 0, 223 ColPos: 0, 224 }, 225 }, 226 }) 227 args = append(args, &plan.Expr{ 228 Typ: plan.Type{ 229 Id: int32(ts[0].Oid), 230 }, 231 Expr: &plan.Expr_Col{ 232 Col: &plan.ColRef{ 233 RelPos: 1, 234 ColPos: 0, 235 }, 236 }, 237 }) 238 cond := &plan.Expr{ 239 Typ: plan.Type{ 240 Id: int32(types.T_bool), 241 }, 242 Expr: &plan.Expr_F{ 243 F: &plan.Function{ 244 Args: args, 245 Func: &plan.ObjectRef{Obj: fid, ObjName: "="}, 246 }, 247 }, 248 } 249 return joinTestCase{ 250 types: ts, 251 flgs: flgs, 252 proc: proc, 253 cancel: cancel, 254 arg: &Argument{ 255 RightTypes: ts, 256 Result: rp, 257 Conditions: cs, 258 NumCPU: 1, 259 IsMerger: true, 260 Cond: cond, 261 OperatorBase: vm.OperatorBase{ 262 OperatorInfo: vm.OperatorInfo{ 263 Idx: 0, 264 IsFirst: false, 265 IsLast: false, 266 }, 267 }, 268 }, 269 barg: &hashbuild.Argument{ 270 Typs: ts, 271 NeedHashMap: true, 272 Conditions: cs[1], 273 OperatorBase: vm.OperatorBase{ 274 OperatorInfo: vm.OperatorInfo{ 275 Idx: 0, 276 IsFirst: false, 277 IsLast: false, 278 }, 279 }, 280 NeedAllocateSels: true, 281 }, 282 } 283 } 284 285 func hashBuild(t *testing.T, tc joinTestCase) []*batch.Batch { 286 err := tc.barg.Prepare(tc.proc) 287 require.NoError(t, err) 288 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 289 for _, r := range tc.proc.Reg.MergeReceivers { 290 r.Ch <- nil 291 } 292 ok1, err := tc.barg.Call(tc.proc) 293 require.NoError(t, err) 294 require.Equal(t, false, ok1.Status == vm.ExecStop) 295 ok2, err := tc.barg.Call(tc.proc) 296 require.NoError(t, err) 297 require.Equal(t, false, ok2.Status == vm.ExecStop) 298 return []*batch.Batch{ok1.Batch, ok2.Batch} 299 } 300 301 // create a new block based on the type information, flgs[i] == ture: has null 302 func newBatch(ts []types.Type, proc *process.Process, rows int64) *batch.Batch { 303 return testutil.NewBatch(ts, false, int(rows), proc.Mp()) 304 }