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