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