github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/colexec/left/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 left 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/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{{Oid: types.T_int8}}, []colexec.ResultPos{colexec.NewResultPos(0, 0)}, 57 [][]*plan.Expr{ 58 { 59 newExpr(0, types.Type{Oid: types.T_int8}), 60 }, 61 { 62 newExpr(0, types.Type{Oid: types.T_int8}), 63 }, 64 }), 65 newTestCase([]bool{true}, []types.Type{{Oid: types.T_int8}}, []colexec.ResultPos{colexec.NewResultPos(0, 0), colexec.NewResultPos(1, 0)}, 66 [][]*plan.Expr{ 67 { 68 newExpr(0, types.Type{Oid: types.T_int8}), 69 }, 70 { 71 newExpr(0, types.Type{Oid: types.T_int8}), 72 }, 73 }), 74 } 75 } 76 77 func TestString(t *testing.T) { 78 buf := new(bytes.Buffer) 79 for _, tc := range tcs { 80 String(tc.arg, buf) 81 } 82 } 83 84 func TestJoin(t *testing.T) { 85 for _, tc := range tcs { 86 nb0 := tc.proc.Mp().CurrNB() 87 bat := hashBuild(t, tc) 88 if jm, ok := bat.Ht.(*hashmap.JoinMap); ok { 89 jm.SetDupCount(int64(1)) 90 } 91 err := Prepare(tc.proc, tc.arg) 92 require.NoError(t, err) 93 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows) 94 tc.proc.Reg.MergeReceivers[0].Ch <- &batch.Batch{} 95 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows) 96 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows) 97 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows) 98 tc.proc.Reg.MergeReceivers[0].Ch <- nil 99 tc.proc.Reg.MergeReceivers[1].Ch <- bat 100 for { 101 if ok, err := Call(0, tc.proc, tc.arg, false, false); ok || err != nil { 102 break 103 } 104 tc.proc.Reg.InputBatch.Clean(tc.proc.Mp()) 105 } 106 nb1 := tc.proc.Mp().CurrNB() 107 require.Equal(t, nb0, nb1) 108 } 109 for _, tc := range tcs { 110 nb0 := tc.proc.Mp().CurrNB() 111 err := Prepare(tc.proc, tc.arg) 112 require.NoError(t, err) 113 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows) 114 tc.proc.Reg.MergeReceivers[0].Ch <- &batch.Batch{} 115 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows) 116 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows) 117 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows) 118 tc.proc.Reg.MergeReceivers[0].Ch <- nil 119 tc.proc.Reg.MergeReceivers[1].Ch <- nil 120 for { 121 if ok, err := Call(0, tc.proc, tc.arg, false, false); ok || err != nil { 122 break 123 } 124 tc.proc.Reg.InputBatch.Clean(tc.proc.Mp()) 125 } 126 nb1 := tc.proc.Mp().CurrNB() 127 tc.arg.Free(tc.proc, false) 128 require.Equal(t, nb0, nb1) 129 } 130 } 131 132 func BenchmarkJoin(b *testing.B) { 133 for i := 0; i < b.N; i++ { 134 tcs = []joinTestCase{ 135 newTestCase([]bool{false}, []types.Type{{Oid: types.T_int8}}, []colexec.ResultPos{colexec.NewResultPos(0, 0), colexec.NewResultPos(1, 0)}, 136 [][]*plan.Expr{ 137 { 138 newExpr(0, types.Type{Oid: types.T_int8}), 139 }, 140 { 141 newExpr(0, types.Type{Oid: types.T_int8}), 142 }, 143 }), 144 newTestCase([]bool{true}, []types.Type{{Oid: types.T_int8}}, []colexec.ResultPos{colexec.NewResultPos(0, 0), colexec.NewResultPos(1, 0)}, 145 [][]*plan.Expr{ 146 { 147 newExpr(0, types.Type{Oid: types.T_int8}), 148 }, 149 { 150 newExpr(0, types.Type{Oid: types.T_int8}), 151 }, 152 }), 153 } 154 t := new(testing.T) 155 for _, tc := range tcs { 156 bat := hashBuild(t, tc) 157 err := Prepare(tc.proc, tc.arg) 158 require.NoError(t, err) 159 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows) 160 tc.proc.Reg.MergeReceivers[0].Ch <- &batch.Batch{} 161 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows) 162 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows) 163 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows) 164 tc.proc.Reg.MergeReceivers[0].Ch <- nil 165 tc.proc.Reg.MergeReceivers[1].Ch <- bat 166 for { 167 if ok, err := Call(0, tc.proc, tc.arg, false, false); ok || err != nil { 168 break 169 } 170 tc.proc.Reg.InputBatch.Clean(tc.proc.Mp()) 171 } 172 } 173 } 174 } 175 176 func newExpr(pos int32, typ types.Type) *plan.Expr { 177 return &plan.Expr{ 178 Typ: &plan.Type{ 179 Size: typ.Size, 180 Scale: typ.Scale, 181 Width: typ.Width, 182 Id: int32(typ.Oid), 183 }, 184 Expr: &plan.Expr_Col{ 185 Col: &plan.ColRef{ 186 ColPos: pos, 187 }, 188 }, 189 } 190 } 191 192 func newTestCase(flgs []bool, ts []types.Type, rp []colexec.ResultPos, cs [][]*plan.Expr) joinTestCase { 193 proc := testutil.NewProcessWithMPool(mpool.MustNewZero()) 194 proc.Reg.MergeReceivers = make([]*process.WaitRegister, 2) 195 ctx, cancel := context.WithCancel(context.Background()) 196 proc.Reg.MergeReceivers[0] = &process.WaitRegister{ 197 Ctx: ctx, 198 Ch: make(chan *batch.Batch, 10), 199 } 200 proc.Reg.MergeReceivers[1] = &process.WaitRegister{ 201 Ctx: ctx, 202 Ch: make(chan *batch.Batch, 3), 203 } 204 fid := function.EncodeOverloadID(function.EQUAL, 4) 205 args := make([]*plan.Expr, 0, 2) 206 args = append(args, &plan.Expr{ 207 Typ: &plan.Type{ 208 Size: ts[0].Size, 209 Id: int32(ts[0].Oid), 210 }, 211 Expr: &plan.Expr_Col{ 212 Col: &plan.ColRef{ 213 RelPos: 0, 214 ColPos: 0, 215 }, 216 }, 217 }) 218 args = append(args, &plan.Expr{ 219 Typ: &plan.Type{ 220 Size: ts[0].Size, 221 Id: int32(ts[0].Oid), 222 }, 223 Expr: &plan.Expr_Col{ 224 Col: &plan.ColRef{ 225 RelPos: 1, 226 ColPos: 0, 227 }, 228 }, 229 }) 230 cond := &plan.Expr{ 231 Typ: &plan.Type{ 232 Size: 1, 233 Id: int32(types.T_bool), 234 }, 235 Expr: &plan.Expr_F{ 236 F: &plan.Function{ 237 Args: args, 238 Func: &plan.ObjectRef{Obj: fid, ObjName: "="}, 239 }, 240 }, 241 } 242 return joinTestCase{ 243 types: ts, 244 flgs: flgs, 245 proc: proc, 246 cancel: cancel, 247 arg: &Argument{ 248 Typs: ts, 249 Result: rp, 250 Conditions: cs, 251 Cond: cond, 252 }, 253 barg: &hashbuild.Argument{ 254 Typs: ts, 255 NeedHashMap: true, 256 Conditions: cs[1], 257 }, 258 } 259 } 260 261 func hashBuild(t *testing.T, tc joinTestCase) *batch.Batch { 262 err := hashbuild.Prepare(tc.proc, tc.barg) 263 require.NoError(t, err) 264 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows) 265 tc.proc.Reg.MergeReceivers[0].Ch <- nil 266 ok, err := hashbuild.Call(0, tc.proc, tc.barg, false, false) 267 require.NoError(t, err) 268 require.Equal(t, true, ok) 269 return tc.proc.Reg.InputBatch 270 } 271 272 // create a new block based on the type information, flgs[i] == ture: has null 273 func newBatch(t *testing.T, flgs []bool, ts []types.Type, proc *process.Process, rows int64) *batch.Batch { 274 return testutil.NewBatch(ts, false, int(rows), proc.Mp()) 275 }