github.com/matrixorigin/matrixone@v1.2.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" 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{types.T_int8.ToType()}, []colexec.ResultPos{colexec.NewResultPos(0, 0), colexec.NewResultPos(1, 0)}), 57 newTestCase([]bool{true}, []types.Type{types.T_int8.ToType()}, []colexec.ResultPos{colexec.NewResultPos(0, 0), colexec.NewResultPos(1, 0)}), 58 } 59 } 60 61 func TestString(t *testing.T) { 62 buf := new(bytes.Buffer) 63 for _, tc := range tcs { 64 tc.arg.String(buf) 65 } 66 } 67 68 func TestJoin(t *testing.T) { 69 for _, tc := range tcs { 70 bats := hashBuild(t, tc) 71 err := tc.arg.Prepare(tc.proc) 72 require.NoError(t, err) 73 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 74 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 75 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 76 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 77 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 78 tc.proc.Reg.MergeReceivers[0].Ch <- nil 79 tc.proc.Reg.MergeReceivers[1].Ch <- bats[1] 80 tc.proc.Reg.MergeReceivers[0].Ch <- nil 81 tc.proc.Reg.MergeReceivers[1].Ch <- nil 82 for { 83 ok, err := tc.arg.Call(tc.proc) 84 if ok.Status == vm.ExecStop || err != nil { 85 break 86 } 87 } 88 tc.arg.Free(tc.proc, false, nil) 89 tc.proc.FreeVectors() 90 require.Equal(t, int64(0), tc.proc.Mp().CurrNB()) 91 } 92 93 for _, tc := range tcs { 94 err := tc.arg.Prepare(tc.proc) 95 require.NoError(t, err) 96 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 97 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 98 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 99 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 100 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 101 tc.proc.Reg.MergeReceivers[0].Ch <- nil 102 tc.proc.Reg.MergeReceivers[1].Ch <- nil 103 tc.proc.Reg.MergeReceivers[0].Ch <- nil 104 tc.proc.Reg.MergeReceivers[1].Ch <- nil 105 for { 106 ok, err := tc.arg.Call(tc.proc) 107 if ok.Status == vm.ExecStop || err != nil { 108 break 109 } 110 } 111 tc.arg.Free(tc.proc, false, nil) 112 tc.proc.FreeVectors() 113 require.Equal(t, int64(0), tc.proc.Mp().CurrNB()) 114 } 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{types.T_int8.ToType()}, []colexec.ResultPos{colexec.NewResultPos(0, 0), colexec.NewResultPos(1, 0)}), 122 newTestCase([]bool{true}, []types.Type{types.T_int8.ToType()}, []colexec.ResultPos{colexec.NewResultPos(0, 0), colexec.NewResultPos(1, 0)}), 123 } 124 t := new(testing.T) 125 for _, tc := range tcs { 126 bats := hashBuild(t, tc) 127 err := tc.arg.Prepare(tc.proc) 128 require.NoError(t, err) 129 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 130 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 131 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 132 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 133 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 134 tc.proc.Reg.MergeReceivers[0].Ch <- nil 135 tc.proc.Reg.MergeReceivers[1].Ch <- bats[1] 136 for { 137 ok, err := tc.arg.Call(tc.proc) 138 if ok.Status == vm.ExecStop || err != nil { 139 break 140 } 141 } 142 } 143 } 144 } 145 146 func newTestCase(flgs []bool, ts []types.Type, rp []colexec.ResultPos) joinTestCase { 147 proc := testutil.NewProcessWithMPool(mpool.MustNewZero()) 148 proc.Reg.MergeReceivers = make([]*process.WaitRegister, 2) 149 ctx, cancel := context.WithCancel(context.Background()) 150 proc.Reg.MergeReceivers[0] = &process.WaitRegister{ 151 Ctx: ctx, 152 Ch: make(chan *batch.Batch, 10), 153 } 154 proc.Reg.MergeReceivers[1] = &process.WaitRegister{ 155 Ctx: ctx, 156 Ch: make(chan *batch.Batch, 4), 157 } 158 fr, _ := function.GetFunctionByName(ctx, "=", ts) 159 fid := fr.GetEncodedOverloadID() 160 args := make([]*plan.Expr, 0, 2) 161 args = append(args, &plan.Expr{ 162 Typ: plan.Type{ 163 Id: int32(ts[0].Oid), 164 }, 165 Expr: &plan.Expr_Col{ 166 Col: &plan.ColRef{ 167 RelPos: 0, 168 ColPos: 0, 169 }, 170 }, 171 }) 172 args = append(args, &plan.Expr{ 173 Typ: plan.Type{ 174 Id: int32(ts[0].Oid), 175 }, 176 Expr: &plan.Expr_Col{ 177 Col: &plan.ColRef{ 178 RelPos: 1, 179 ColPos: 0, 180 }, 181 }, 182 }) 183 cond := &plan.Expr{ 184 Typ: plan.Type{ 185 Id: int32(types.T_bool), 186 }, 187 Expr: &plan.Expr_F{ 188 F: &plan.Function{ 189 Args: args, 190 Func: &plan.ObjectRef{Obj: fid, ObjName: "="}, 191 }, 192 }, 193 } 194 return joinTestCase{ 195 types: ts, 196 flgs: flgs, 197 proc: proc, 198 cancel: cancel, 199 arg: &Argument{ 200 Typs: ts, 201 Cond: cond, 202 Result: rp, 203 OperatorBase: vm.OperatorBase{ 204 OperatorInfo: vm.OperatorInfo{ 205 Idx: 0, 206 IsFirst: false, 207 IsLast: false, 208 }, 209 }, 210 }, 211 barg: &hashbuild.Argument{ 212 Typs: ts, 213 OperatorBase: vm.OperatorBase{ 214 OperatorInfo: vm.OperatorInfo{ 215 Idx: 0, 216 IsFirst: false, 217 IsLast: false, 218 }, 219 }, 220 }, 221 } 222 } 223 224 func hashBuild(t *testing.T, tc joinTestCase) []*batch.Batch { 225 err := tc.barg.Prepare(tc.proc) 226 require.NoError(t, err) 227 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 228 for _, r := range tc.proc.Reg.MergeReceivers { 229 r.Ch <- nil 230 } 231 ok1, err := tc.barg.Call(tc.proc) 232 require.NoError(t, err) 233 require.Equal(t, false, ok1.Status == vm.ExecStop) 234 ok2, err := tc.barg.Call(tc.proc) 235 require.NoError(t, err) 236 require.Equal(t, false, ok2.Status == vm.ExecStop) 237 return []*batch.Batch{ok1.Batch, ok2.Batch} 238 } 239 240 // create a new block based on the type information, flgs[i] == ture: has null 241 func newBatch(ts []types.Type, proc *process.Process, rows int64) *batch.Batch { 242 return testutil.NewBatch(ts, false, int(rows), proc.Mp()) 243 }