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