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