github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/colexec/right/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 right 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" 28 "github.com/matrixorigin/matrixone/pkg/sql/colexec/hashbuild" 29 "github.com/matrixorigin/matrixone/pkg/sql/plan/function" 30 "github.com/matrixorigin/matrixone/pkg/testutil" 31 "github.com/matrixorigin/matrixone/pkg/vm" 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 joinTestCase struct { 43 arg *Argument 44 flgs []bool // flgs[i] == true: nullable 45 types []types.Type 46 proc *process.Process 47 cancel context.CancelFunc 48 barg *hashbuild.Argument 49 } 50 51 var ( 52 tcs []joinTestCase 53 ) 54 55 func init() { 56 tcs = []joinTestCase{ 57 newTestCase([]bool{false}, []types.Type{types.T_int8.ToType()}, []colexec.ResultPos{colexec.NewResultPos(0, 0)}, 58 [][]*plan.Expr{ 59 { 60 newExpr(0, types.T_int8.ToType()), 61 }, 62 { 63 newExpr(0, types.T_int8.ToType()), 64 }, 65 }), 66 newTestCase([]bool{true}, []types.Type{types.T_int8.ToType()}, []colexec.ResultPos{colexec.NewResultPos(0, 0), colexec.NewResultPos(1, 0)}, 67 [][]*plan.Expr{ 68 { 69 newExpr(0, types.T_int8.ToType()), 70 }, 71 { 72 newExpr(0, types.T_int8.ToType()), 73 }, 74 }), 75 } 76 } 77 78 func TestString(t *testing.T) { 79 buf := new(bytes.Buffer) 80 for _, tc := range tcs { 81 tc.arg.String(buf) 82 } 83 } 84 85 func TestJoin(t *testing.T) { 86 for _, tc := range tcs { 87 nb0 := tc.proc.Mp().CurrNB() 88 bats := hashBuild(t, tc) 89 if jm, ok := bats[0].AuxData.(*hashmap.JoinMap); ok { 90 jm.SetDupCount(int64(1)) 91 } 92 err := tc.arg.Prepare(tc.proc) 93 require.NoError(t, err) 94 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 95 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 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 <- newBatch(tc.types, tc.proc, Rows) 99 tc.proc.Reg.MergeReceivers[0].Ch <- nil 100 tc.proc.Reg.MergeReceivers[1].Ch <- bats[0] 101 tc.proc.Reg.MergeReceivers[1].Ch <- bats[1] 102 tc.proc.Reg.MergeReceivers[0].Ch <- nil 103 tc.proc.Reg.MergeReceivers[1].Ch <- nil 104 for { 105 ok, err := tc.arg.Call(tc.proc) 106 if ok.Status == vm.ExecStop || err != nil { 107 break 108 } 109 } 110 tc.arg.Free(tc.proc, false, nil) 111 tc.proc.FreeVectors() 112 nb1 := tc.proc.Mp().CurrNB() 113 require.Equal(t, nb0, nb1) 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()}, []colexec.ResultPos{colexec.NewResultPos(0, 0), colexec.NewResultPos(1, 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()}, []colexec.ResultPos{colexec.NewResultPos(0, 0), colexec.NewResultPos(1, 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 []colexec.ResultPos, 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 LeftTypes: ts, 256 RightTypes: ts, 257 Result: rp, 258 Conditions: cs, 259 NumCPU: 1, 260 IsMerger: true, 261 Cond: cond, 262 OperatorBase: vm.OperatorBase{ 263 OperatorInfo: vm.OperatorInfo{ 264 Idx: 0, 265 IsFirst: false, 266 IsLast: false, 267 }, 268 }, 269 }, 270 barg: &hashbuild.Argument{ 271 Typs: ts, 272 NeedHashMap: true, 273 Conditions: cs[1], 274 OperatorBase: vm.OperatorBase{ 275 OperatorInfo: vm.OperatorInfo{ 276 Idx: 0, 277 IsFirst: false, 278 IsLast: false, 279 }, 280 }, 281 NeedAllocateSels: true, 282 NeedMergedBatch: true, 283 }, 284 } 285 } 286 287 func hashBuild(t *testing.T, tc joinTestCase) []*batch.Batch { 288 err := tc.barg.Prepare(tc.proc) 289 require.NoError(t, err) 290 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 291 for _, r := range tc.proc.Reg.MergeReceivers { 292 r.Ch <- nil 293 } 294 ok1, err := tc.barg.Call(tc.proc) 295 require.NoError(t, err) 296 require.Equal(t, false, ok1.Status == vm.ExecStop) 297 ok2, err := tc.barg.Call(tc.proc) 298 require.NoError(t, err) 299 require.Equal(t, false, ok2.Status == vm.ExecStop) 300 return []*batch.Batch{ok1.Batch, ok2.Batch} 301 } 302 303 // create a new block based on the type information, flgs[i] == ture: has null 304 func newBatch(ts []types.Type, proc *process.Process, rows int64) *batch.Batch { 305 return testutil.NewBatch(ts, false, int(rows), proc.Mp()) 306 }