github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/interlock/joiner.go (about) 1 // Copyright 2020 WHTCORPS INC, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package interlock 15 16 import ( 17 causetembedded "github.com/whtcorpsinc/milevadb/causet/embedded" 18 "github.com/whtcorpsinc/milevadb/memex" 19 "github.com/whtcorpsinc/milevadb/soliton/chunk" 20 "github.com/whtcorpsinc/milevadb/soliton/logutil" 21 "github.com/whtcorpsinc/milevadb/stochastikctx" 22 "github.com/whtcorpsinc/milevadb/types" 23 "go.uber.org/zap" 24 ) 25 26 var ( 27 _ joiner = &semiJoiner{} 28 _ joiner = &antiSemiJoiner{} 29 _ joiner = &leftOuterSemiJoiner{} 30 _ joiner = &antiLeftOuterSemiJoiner{} 31 _ joiner = &leftOuterJoiner{} 32 _ joiner = &rightOuterJoiner{} 33 _ joiner = &innerJoiner{} 34 ) 35 36 // joiner is used to generate join results according to the join type. 37 // A typical instruction flow is: 38 // 39 // hasMatch, hasNull := false, false 40 // for innerIter.Current() != innerIter.End() { 41 // matched, isNull, err := j.tryToMatchInners(outer, innerIter, chk) 42 // // handle err 43 // hasMatch = hasMatch || matched 44 // hasNull = hasNull || isNull 45 // } 46 // if !hasMatch { 47 // j.onMissMatch(hasNull, outer, chk) 48 // } 49 // 50 // NOTE: This interface is **not** thread-safe. 51 // TODO: unit test 52 // for all join type 53 // 1. no filter, no inline projection 54 // 2. no filter, inline projection 55 // 3. no filter, inline projection to empty defCausumn 56 // 4. filter, no inline projection 57 // 5. filter, inline projection 58 // 6. filter, inline projection to empty defCausumn 59 type joiner interface { 60 // tryToMatchInners tries to join an outer event with a batch of inner rows. When 61 // 'inners.Len != 0' but all the joined rows are filtered, the outer event is 62 // considered unmatched. Otherwise, the outer event is matched and some joined 63 // rows are appended to `chk`. The size of `chk` is limited to MaxChunkSize. 64 // Note that when the outer event is considered unmatched, we need to differentiate 65 // whether the join conditions return null or false, because that matters for 66 // AntiSemiJoin/LeftOuterSemiJoin/AntiLeftOuterSemiJoin, by setting the return 67 // value isNull; for other join types, isNull is always false. 68 // 69 // NOTE: Callers need to call this function multiple times to consume all 70 // the inner rows for an outer event, and decide whether the outer event can be 71 // matched with at lease one inner event. 72 tryToMatchInners(outer chunk.Event, inners chunk.Iterator, chk *chunk.Chunk) (matched bool, isNull bool, err error) 73 74 // tryToMatchOuters tries to join a batch of outer rows with one inner event. 75 // It's used when the join is an outer join and the hash causet is built 76 // using the outer side. 77 tryToMatchOuters(outer chunk.Iterator, inner chunk.Event, chk *chunk.Chunk, outerEventStatus []outerEventStatusFlag) (_ []outerEventStatusFlag, err error) 78 79 // onMissMatch operates on the unmatched outer event according to the join 80 // type. An outer event can be considered miss matched if: 81 // 1. it can not pass the filter on the outer causet side. 82 // 2. there is no inner event with the same join key. 83 // 3. all the joined rows can not pass the filter on the join result. 84 // 85 // On these conditions, the caller calls this function to handle the 86 // unmatched outer rows according to the current join type: 87 // 1. 'SemiJoin': ignores the unmatched outer event. 88 // 2. 'AntiSemiJoin': appends the unmatched outer event to the result buffer. 89 // 3. 'LeftOuterSemiJoin': concats the unmatched outer event with 0 and 90 // appends it to the result buffer. 91 // 4. 'AntiLeftOuterSemiJoin': concats the unmatched outer event with 1 and 92 // appends it to the result buffer. 93 // 5. 'LeftOuterJoin': concats the unmatched outer event with a event of NULLs 94 // and appends it to the result buffer. 95 // 6. 'RightOuterJoin': concats the unmatched outer event with a event of NULLs 96 // and appends it to the result buffer. 97 // 7. 'InnerJoin': ignores the unmatched outer event. 98 // 99 // Note that, for LeftOuterSemiJoin, AntiSemiJoin and AntiLeftOuterSemiJoin, 100 // we need to know the reason of outer event being treated as unmatched: 101 // whether the join condition returns false, or returns null, because 102 // it decides if this outer event should be outputted, hence we have a `hasNull` 103 // parameter passed to `onMissMatch`. 104 onMissMatch(hasNull bool, outer chunk.Event, chk *chunk.Chunk) 105 106 // Clone deep copies a joiner. 107 Clone() joiner 108 } 109 110 // JoinerType returns the join type of a Joiner. 111 func JoinerType(j joiner) causetembedded.JoinType { 112 switch j.(type) { 113 case *semiJoiner: 114 return causetembedded.SemiJoin 115 case *antiSemiJoiner: 116 return causetembedded.AntiSemiJoin 117 case *leftOuterSemiJoiner: 118 return causetembedded.LeftOuterSemiJoin 119 case *antiLeftOuterSemiJoiner: 120 return causetembedded.AntiLeftOuterSemiJoin 121 case *leftOuterJoiner: 122 return causetembedded.LeftOuterJoin 123 case *rightOuterJoiner: 124 return causetembedded.RightOuterJoin 125 default: 126 return causetembedded.InnerJoin 127 } 128 } 129 130 func newJoiner(ctx stochastikctx.Context, joinType causetembedded.JoinType, 131 outerIsRight bool, defaultInner []types.Causet, filter []memex.Expression, 132 lhsDefCausTypes, rhsDefCausTypes []*types.FieldType, childrenUsed [][]bool) joiner { 133 base := baseJoiner{ 134 ctx: ctx, 135 conditions: filter, 136 outerIsRight: outerIsRight, 137 maxChunkSize: ctx.GetStochastikVars().MaxChunkSize, 138 } 139 base.selected = make([]bool, 0, chunk.InitialCapacity) 140 base.isNull = make([]bool, 0, chunk.InitialCapacity) 141 if childrenUsed != nil { 142 base.lUsed = make([]int, 0, len(childrenUsed[0])) // make it non-nil 143 for i, used := range childrenUsed[0] { 144 if used { 145 base.lUsed = append(base.lUsed, i) 146 } 147 } 148 base.rUsed = make([]int, 0, len(childrenUsed[1])) // make it non-nil 149 for i, used := range childrenUsed[1] { 150 if used { 151 base.rUsed = append(base.rUsed, i) 152 } 153 } 154 logutil.BgLogger().Debug("InlineProjection", 155 zap.Ints("lUsed", base.lUsed), zap.Ints("rUsed", base.rUsed), 156 zap.Int("lCount", len(lhsDefCausTypes)), zap.Int("rCount", len(rhsDefCausTypes))) 157 } 158 if joinType == causetembedded.LeftOuterJoin || joinType == causetembedded.RightOuterJoin { 159 innerDefCausTypes := lhsDefCausTypes 160 if !outerIsRight { 161 innerDefCausTypes = rhsDefCausTypes 162 } 163 base.initDefaultInner(innerDefCausTypes, defaultInner) 164 } 165 // shallowEventType may be different with the output defCausumns because output defCausumns may 166 // be pruned inline, while shallow event should not be because each defCausumn may need 167 // be used in filter. 168 shallowEventType := make([]*types.FieldType, 0, len(lhsDefCausTypes)+len(rhsDefCausTypes)) 169 shallowEventType = append(shallowEventType, lhsDefCausTypes...) 170 shallowEventType = append(shallowEventType, rhsDefCausTypes...) 171 switch joinType { 172 case causetembedded.SemiJoin: 173 base.shallowEvent = chunk.MutEventFromTypes(shallowEventType) 174 return &semiJoiner{base} 175 case causetembedded.AntiSemiJoin: 176 base.shallowEvent = chunk.MutEventFromTypes(shallowEventType) 177 return &antiSemiJoiner{base} 178 case causetembedded.LeftOuterSemiJoin: 179 base.shallowEvent = chunk.MutEventFromTypes(shallowEventType) 180 return &leftOuterSemiJoiner{base} 181 case causetembedded.AntiLeftOuterSemiJoin: 182 base.shallowEvent = chunk.MutEventFromTypes(shallowEventType) 183 return &antiLeftOuterSemiJoiner{base} 184 case causetembedded.LeftOuterJoin, causetembedded.RightOuterJoin, causetembedded.InnerJoin: 185 if len(base.conditions) > 0 { 186 base.chk = chunk.NewChunkWithCapacity(shallowEventType, ctx.GetStochastikVars().MaxChunkSize) 187 } 188 switch joinType { 189 case causetembedded.LeftOuterJoin: 190 return &leftOuterJoiner{base} 191 case causetembedded.RightOuterJoin: 192 return &rightOuterJoiner{base} 193 case causetembedded.InnerJoin: 194 return &innerJoiner{base} 195 } 196 } 197 panic("unsupported join type in func newJoiner()") 198 } 199 200 type outerEventStatusFlag byte 201 202 const ( 203 outerEventUnmatched outerEventStatusFlag = iota 204 outerEventMatched 205 outerEventHasNull 206 ) 207 208 type baseJoiner struct { 209 ctx stochastikctx.Context 210 conditions []memex.Expression 211 defaultInner chunk.Event 212 outerIsRight bool 213 chk *chunk.Chunk 214 shallowEvent chunk.MutEvent 215 selected []bool 216 isNull []bool 217 maxChunkSize int 218 219 // lUsed/rUsed show which defCausumns are used by father for left child and right child. 220 // NOTE: 221 // 1. every defCausumns are used if lUsed/rUsed is nil. 222 // 2. no defCausumns are used if lUsed/rUsed is not nil but the size of lUsed/rUsed is 0. 223 lUsed, rUsed []int 224 } 225 226 func (j *baseJoiner) initDefaultInner(innerTypes []*types.FieldType, defaultInner []types.Causet) { 227 mublockEvent := chunk.MutEventFromTypes(innerTypes) 228 mublockEvent.SetCausets(defaultInner[:len(innerTypes)]...) 229 j.defaultInner = mublockEvent.ToEvent() 230 } 231 232 func (j *baseJoiner) makeJoinEventToChunk(chk *chunk.Chunk, lhs, rhs chunk.Event, lUsed, rUsed []int) { 233 // Call AppendEvent() first to increment the virtual rows. 234 // Fix: https://github.com/whtcorpsinc/milevadb/issues/5771 235 lWide := chk.AppendEventByDefCausIdxs(lhs, lUsed) 236 chk.AppendPartialEventByDefCausIdxs(lWide, rhs, rUsed) 237 } 238 239 // makeShallowJoinEvent shallow copies `inner` and `outer` into `shallowEvent`. 240 // It should not consider `j.lUsed` and `j.rUsed`, because the defCausumns which 241 // need to be used in `j.conditions` may not exist in outputs. 242 func (j *baseJoiner) makeShallowJoinEvent(isRightJoin bool, inner, outer chunk.Event) { 243 if !isRightJoin { 244 inner, outer = outer, inner 245 } 246 j.shallowEvent.ShallowCopyPartialEvent(0, inner) 247 j.shallowEvent.ShallowCopyPartialEvent(inner.Len(), outer) 248 } 249 250 // filter is used to filter the result constructed by tryToMatchInners, the result is 251 // built by one outer event and multiple inner rows. The returned bool value 252 // indicates whether the outer event matches any inner rows. 253 func (j *baseJoiner) filter( 254 input, output *chunk.Chunk, outerDefCausLen int, 255 lUsed, rUsed []int) (bool, error) { 256 257 var err error 258 j.selected, err = memex.VectorizedFilter(j.ctx, j.conditions, chunk.NewIterator4Chunk(input), j.selected) 259 if err != nil { 260 return false, err 261 } 262 // Batch copies selected rows to output chunk. 263 innerDefCausOffset, outerDefCausOffset := 0, input.NumDefCauss()-outerDefCausLen 264 innerDefCausLen := input.NumDefCauss() - outerDefCausLen 265 if !j.outerIsRight { 266 innerDefCausOffset, outerDefCausOffset = outerDefCausLen, 0 267 } 268 if lUsed != nil || rUsed != nil { 269 lSize := outerDefCausOffset 270 if !j.outerIsRight { 271 lSize = innerDefCausOffset 272 } 273 used := make([]int, len(lUsed)+len(rUsed)) 274 copy(used, lUsed) 275 for i := range rUsed { 276 used[i+len(lUsed)] = rUsed[i] + lSize 277 } 278 input = input.Prune(used) 279 280 innerDefCausOffset, outerDefCausOffset = 0, len(lUsed) 281 innerDefCausLen, outerDefCausLen = len(lUsed), len(rUsed) 282 if !j.outerIsRight { 283 innerDefCausOffset, outerDefCausOffset = len(lUsed), 0 284 innerDefCausLen, outerDefCausLen = outerDefCausLen, innerDefCausLen 285 } 286 287 } 288 return chunk.CopySelectedJoinEventsWithSameOuterEvents(input, innerDefCausOffset, innerDefCausLen, outerDefCausOffset, outerDefCausLen, j.selected, output) 289 } 290 291 // filterAndCheckOuterEventStatus is used to filter the result constructed by 292 // tryToMatchOuters, the result is built by multiple outer rows and one inner 293 // event. The returned outerEventStatusFlag slice value indicates the status of 294 // each outer event (matched/unmatched/hasNull). 295 func (j *baseJoiner) filterAndCheckOuterEventStatus( 296 input, output *chunk.Chunk, innerDefCaussLen int, outerEventStatus []outerEventStatusFlag, 297 lUsed, rUsed []int) ([]outerEventStatusFlag, error) { 298 299 var err error 300 j.selected, j.isNull, err = memex.VectorizedFilterConsiderNull(j.ctx, j.conditions, chunk.NewIterator4Chunk(input), j.selected, j.isNull) 301 if err != nil { 302 return nil, err 303 } 304 for i := 0; i < len(j.selected); i++ { 305 if j.isNull[i] { 306 outerEventStatus[i] = outerEventHasNull 307 } else if !j.selected[i] { 308 outerEventStatus[i] = outerEventUnmatched 309 } 310 } 311 312 if lUsed != nil || rUsed != nil { 313 lSize := innerDefCaussLen 314 if !j.outerIsRight { 315 lSize = input.NumDefCauss() - innerDefCaussLen 316 } 317 used := make([]int, len(lUsed)+len(rUsed)) 318 copy(used, lUsed) 319 for i := range rUsed { 320 used[i+len(lUsed)] = rUsed[i] + lSize 321 } 322 input = input.Prune(used) 323 } 324 // Batch copies selected rows to output chunk. 325 _, err = chunk.CopySelectedJoinEventsDirect(input, j.selected, output) 326 return outerEventStatus, err 327 } 328 329 func (j *baseJoiner) Clone() baseJoiner { 330 base := baseJoiner{ 331 ctx: j.ctx, 332 conditions: make([]memex.Expression, 0, len(j.conditions)), 333 outerIsRight: j.outerIsRight, 334 maxChunkSize: j.maxChunkSize, 335 selected: make([]bool, 0, len(j.selected)), 336 isNull: make([]bool, 0, len(j.isNull)), 337 } 338 for _, con := range j.conditions { 339 base.conditions = append(base.conditions, con.Clone()) 340 } 341 if j.chk != nil { 342 base.chk = j.chk.CopyConstruct() 343 } else { 344 base.shallowEvent = j.shallowEvent.Clone() 345 } 346 if !j.defaultInner.IsEmpty() { 347 base.defaultInner = j.defaultInner.CopyConstruct() 348 } 349 if j.lUsed != nil { 350 base.lUsed = make([]int, len(j.lUsed)) 351 copy(base.lUsed, j.lUsed) 352 } 353 if j.rUsed != nil { 354 base.rUsed = make([]int, len(j.rUsed)) 355 copy(base.rUsed, j.rUsed) 356 } 357 return base 358 } 359 360 type semiJoiner struct { 361 baseJoiner 362 } 363 364 func (j *semiJoiner) tryToMatchInners(outer chunk.Event, inners chunk.Iterator, chk *chunk.Chunk) (matched bool, hasNull bool, err error) { 365 if inners.Len() == 0 { 366 return false, false, nil 367 } 368 369 if len(j.conditions) == 0 { 370 chk.AppendEventByDefCausIdxs(outer, j.lUsed) // TODO: need test numVirtualEvent 371 inners.ReachEnd() 372 return true, false, nil 373 } 374 375 for inner := inners.Current(); inner != inners.End(); inner = inners.Next() { 376 j.makeShallowJoinEvent(j.outerIsRight, inner, outer) 377 378 // For SemiJoin, we can safely treat null result of join conditions as false, 379 // so we ignore the nullness returned by EvalBool here. 380 matched, _, err = memex.EvalBool(j.ctx, j.conditions, j.shallowEvent.ToEvent()) 381 if err != nil { 382 return false, false, err 383 } 384 if matched { 385 chk.AppendEventByDefCausIdxs(outer, j.lUsed) 386 inners.ReachEnd() 387 return true, false, nil 388 } 389 } 390 err = inners.Error() 391 return false, false, err 392 } 393 394 func (j *semiJoiner) tryToMatchOuters(outers chunk.Iterator, inner chunk.Event, chk *chunk.Chunk, outerEventStatus []outerEventStatusFlag) (_ []outerEventStatusFlag, err error) { 395 outerEventStatus = outerEventStatus[:0] 396 outer, numToAppend := outers.Current(), chk.RequiredEvents()-chk.NumEvents() 397 if len(j.conditions) == 0 { 398 for ; outer != outers.End() && numToAppend > 0; outer, numToAppend = outers.Next(), numToAppend-1 { 399 chk.AppendEventByDefCausIdxs(outer, j.lUsed) 400 outerEventStatus = append(outerEventStatus, outerEventMatched) 401 } 402 return outerEventStatus, nil 403 } 404 for outer := outers.Current(); outer != outers.End() && numToAppend > 0; outer, numToAppend = outers.Next(), numToAppend-1 { 405 j.makeShallowJoinEvent(j.outerIsRight, inner, outer) 406 // For SemiJoin, we can safely treat null result of join conditions as false, 407 // so we ignore the nullness returned by EvalBool here. 408 matched, _, err := memex.EvalBool(j.ctx, j.conditions, j.shallowEvent.ToEvent()) 409 if err != nil { 410 return outerEventStatus, err 411 } 412 if matched { 413 outerEventStatus = append(outerEventStatus, outerEventMatched) 414 chk.AppendEventByDefCausIdxs(outer, j.lUsed) 415 } else { 416 outerEventStatus = append(outerEventStatus, outerEventUnmatched) 417 } 418 } 419 err = outers.Error() 420 return outerEventStatus, err 421 } 422 423 func (j *semiJoiner) onMissMatch(_ bool, outer chunk.Event, chk *chunk.Chunk) { 424 } 425 426 // Clone implements joiner interface. 427 func (j *semiJoiner) Clone() joiner { 428 return &semiJoiner{baseJoiner: j.baseJoiner.Clone()} 429 } 430 431 type antiSemiJoiner struct { 432 baseJoiner 433 } 434 435 // tryToMatchInners implements joiner interface. 436 func (j *antiSemiJoiner) tryToMatchInners(outer chunk.Event, inners chunk.Iterator, chk *chunk.Chunk) (matched bool, hasNull bool, err error) { 437 if inners.Len() == 0 { 438 return false, false, nil 439 } 440 441 if len(j.conditions) == 0 { 442 inners.ReachEnd() 443 return true, false, nil 444 } 445 446 for inner := inners.Current(); inner != inners.End(); inner = inners.Next() { 447 j.makeShallowJoinEvent(j.outerIsRight, inner, outer) 448 449 matched, isNull, err := memex.EvalBool(j.ctx, j.conditions, j.shallowEvent.ToEvent()) 450 if err != nil { 451 return false, false, err 452 } 453 if matched { 454 inners.ReachEnd() 455 return true, false, nil 456 } 457 hasNull = hasNull || isNull 458 } 459 err = inners.Error() 460 return false, hasNull, err 461 } 462 463 func (j *antiSemiJoiner) tryToMatchOuters(outers chunk.Iterator, inner chunk.Event, chk *chunk.Chunk, outerEventStatus []outerEventStatusFlag) (_ []outerEventStatusFlag, err error) { 464 outerEventStatus = outerEventStatus[:0] 465 numToAppend := chk.RequiredEvents() - chk.NumEvents() 466 if len(j.conditions) == 0 { 467 for ; outers.Current() != outers.End(); outers.Next() { 468 outerEventStatus = append(outerEventStatus, outerEventMatched) 469 } 470 return outerEventStatus, nil 471 } 472 for outer := outers.Current(); outer != outers.End() && numToAppend > 0; outer, numToAppend = outers.Next(), numToAppend-1 { 473 j.makeShallowJoinEvent(j.outerIsRight, inner, outer) 474 matched, isNull, err := memex.EvalBool(j.ctx, j.conditions, j.shallowEvent.ToEvent()) 475 if err != nil { 476 return outerEventStatus, err 477 } 478 if matched { 479 outerEventStatus = append(outerEventStatus, outerEventMatched) 480 } else if isNull { 481 outerEventStatus = append(outerEventStatus, outerEventHasNull) 482 } else { 483 outerEventStatus = append(outerEventStatus, outerEventUnmatched) 484 } 485 } 486 err = outers.Error() 487 return outerEventStatus, err 488 } 489 490 func (j *antiSemiJoiner) onMissMatch(hasNull bool, outer chunk.Event, chk *chunk.Chunk) { 491 if !hasNull { 492 chk.AppendEventByDefCausIdxs(outer, j.lUsed) 493 } 494 } 495 496 func (j *antiSemiJoiner) Clone() joiner { 497 return &antiSemiJoiner{baseJoiner: j.baseJoiner.Clone()} 498 } 499 500 type leftOuterSemiJoiner struct { 501 baseJoiner 502 } 503 504 // tryToMatchInners implements joiner interface. 505 func (j *leftOuterSemiJoiner) tryToMatchInners(outer chunk.Event, inners chunk.Iterator, chk *chunk.Chunk) (matched bool, hasNull bool, err error) { 506 if inners.Len() == 0 { 507 return false, false, nil 508 } 509 510 if len(j.conditions) == 0 { 511 j.onMatch(outer, chk) 512 inners.ReachEnd() 513 return true, false, nil 514 } 515 516 for inner := inners.Current(); inner != inners.End(); inner = inners.Next() { 517 j.makeShallowJoinEvent(false, inner, outer) 518 519 matched, isNull, err := memex.EvalBool(j.ctx, j.conditions, j.shallowEvent.ToEvent()) 520 if err != nil { 521 return false, false, err 522 } 523 if matched { 524 j.onMatch(outer, chk) 525 inners.ReachEnd() 526 return true, false, nil 527 } 528 hasNull = hasNull || isNull 529 } 530 err = inners.Error() 531 return false, hasNull, err 532 } 533 534 func (j *leftOuterSemiJoiner) tryToMatchOuters(outers chunk.Iterator, inner chunk.Event, chk *chunk.Chunk, outerEventStatus []outerEventStatusFlag) (_ []outerEventStatusFlag, err error) { 535 outerEventStatus = outerEventStatus[:0] 536 outer, numToAppend := outers.Current(), chk.RequiredEvents()-chk.NumEvents() 537 if len(j.conditions) == 0 { 538 for ; outer != outers.End() && numToAppend > 0; outer, numToAppend = outers.Next(), numToAppend-1 { 539 j.onMatch(outer, chk) 540 outerEventStatus = append(outerEventStatus, outerEventMatched) 541 } 542 return outerEventStatus, nil 543 } 544 545 for ; outer != outers.End() && numToAppend > 0; outer, numToAppend = outers.Next(), numToAppend-1 { 546 j.makeShallowJoinEvent(false, inner, outer) 547 matched, isNull, err := memex.EvalBool(j.ctx, j.conditions, j.shallowEvent.ToEvent()) 548 if err != nil { 549 return nil, err 550 } 551 if matched { 552 j.onMatch(outer, chk) 553 outerEventStatus = append(outerEventStatus, outerEventMatched) 554 } else if isNull { 555 outerEventStatus = append(outerEventStatus, outerEventHasNull) 556 } else { 557 outerEventStatus = append(outerEventStatus, outerEventUnmatched) 558 } 559 } 560 err = outers.Error() 561 return outerEventStatus, err 562 } 563 564 func (j *leftOuterSemiJoiner) onMatch(outer chunk.Event, chk *chunk.Chunk) { 565 lWide := chk.AppendEventByDefCausIdxs(outer, j.lUsed) 566 chk.AppendInt64(lWide, 1) 567 } 568 569 func (j *leftOuterSemiJoiner) onMissMatch(hasNull bool, outer chunk.Event, chk *chunk.Chunk) { 570 lWide := chk.AppendEventByDefCausIdxs(outer, j.lUsed) 571 if hasNull { 572 chk.AppendNull(lWide) 573 } else { 574 chk.AppendInt64(lWide, 0) 575 } 576 } 577 578 func (j *leftOuterSemiJoiner) Clone() joiner { 579 return &leftOuterSemiJoiner{baseJoiner: j.baseJoiner.Clone()} 580 } 581 582 type antiLeftOuterSemiJoiner struct { 583 baseJoiner 584 } 585 586 // tryToMatchInners implements joiner interface. 587 func (j *antiLeftOuterSemiJoiner) tryToMatchInners(outer chunk.Event, inners chunk.Iterator, chk *chunk.Chunk) (matched bool, hasNull bool, err error) { 588 if inners.Len() == 0 { 589 return false, false, nil 590 } 591 592 if len(j.conditions) == 0 { 593 j.onMatch(outer, chk) 594 inners.ReachEnd() 595 return true, false, nil 596 } 597 598 for inner := inners.Current(); inner != inners.End(); inner = inners.Next() { 599 j.makeShallowJoinEvent(false, inner, outer) 600 601 matched, isNull, err := memex.EvalBool(j.ctx, j.conditions, j.shallowEvent.ToEvent()) 602 if err != nil { 603 return false, false, err 604 } 605 if matched { 606 j.onMatch(outer, chk) 607 inners.ReachEnd() 608 return true, false, nil 609 } 610 hasNull = hasNull || isNull 611 } 612 err = inners.Error() 613 return false, hasNull, err 614 } 615 616 func (j *antiLeftOuterSemiJoiner) tryToMatchOuters(outers chunk.Iterator, inner chunk.Event, chk *chunk.Chunk, outerEventStatus []outerEventStatusFlag) (_ []outerEventStatusFlag, err error) { 617 outerEventStatus = outerEventStatus[:0] 618 outer, numToAppend := outers.Current(), chk.RequiredEvents()-chk.NumEvents() 619 if len(j.conditions) == 0 { 620 for ; outer != outers.End() && numToAppend > 0; outer, numToAppend = outers.Next(), numToAppend-1 { 621 j.onMatch(outer, chk) 622 outerEventStatus = append(outerEventStatus, outerEventMatched) 623 } 624 return outerEventStatus, nil 625 } 626 627 for i := 0; outer != outers.End() && numToAppend > 0; outer, numToAppend, i = outers.Next(), numToAppend-1, i+1 { 628 j.makeShallowJoinEvent(false, inner, outer) 629 matched, isNull, err := memex.EvalBool(j.ctx, j.conditions, j.shallowEvent.ToEvent()) 630 if err != nil { 631 return nil, err 632 } 633 if matched { 634 j.onMatch(outer, chk) 635 outerEventStatus = append(outerEventStatus, outerEventMatched) 636 } else if isNull { 637 outerEventStatus = append(outerEventStatus, outerEventHasNull) 638 } else { 639 outerEventStatus = append(outerEventStatus, outerEventUnmatched) 640 } 641 } 642 err = outers.Error() 643 if err != nil { 644 return 645 } 646 return outerEventStatus, nil 647 } 648 649 func (j *antiLeftOuterSemiJoiner) onMatch(outer chunk.Event, chk *chunk.Chunk) { 650 lWide := chk.AppendEventByDefCausIdxs(outer, j.lUsed) 651 chk.AppendInt64(lWide, 0) 652 } 653 654 func (j *antiLeftOuterSemiJoiner) onMissMatch(hasNull bool, outer chunk.Event, chk *chunk.Chunk) { 655 lWide := chk.AppendEventByDefCausIdxs(outer, j.lUsed) 656 if hasNull { 657 chk.AppendNull(lWide) 658 } else { 659 chk.AppendInt64(lWide, 1) 660 } 661 } 662 663 func (j *antiLeftOuterSemiJoiner) Clone() joiner { 664 return &antiLeftOuterSemiJoiner{baseJoiner: j.baseJoiner.Clone()} 665 } 666 667 type leftOuterJoiner struct { 668 baseJoiner 669 } 670 671 // tryToMatchInners implements joiner interface. 672 func (j *leftOuterJoiner) tryToMatchInners(outer chunk.Event, inners chunk.Iterator, chk *chunk.Chunk) (matched bool, hasNull bool, err error) { 673 if inners.Len() == 0 { 674 return false, false, nil 675 } 676 chkForJoin := chk 677 lUsed, rUsed := j.lUsed, j.rUsed 678 var lUsedForFilter, rUsedForFilter []int 679 if len(j.conditions) > 0 { 680 j.chk.Reset() 681 chkForJoin = j.chk 682 lUsed, rUsed = nil, nil 683 lUsedForFilter, rUsedForFilter = j.lUsed, j.rUsed 684 } 685 686 numToAppend := chk.RequiredEvents() - chk.NumEvents() 687 for ; inners.Current() != inners.End() && numToAppend > 0; numToAppend-- { 688 j.makeJoinEventToChunk(chkForJoin, outer, inners.Current(), lUsed, rUsed) 689 inners.Next() 690 } 691 err = inners.Error() 692 if err != nil { 693 return false, false, err 694 } 695 if len(j.conditions) == 0 { 696 return true, false, nil 697 } 698 699 // reach here, chkForJoin is j.chk 700 matched, err = j.filter(chkForJoin, chk, outer.Len(), lUsedForFilter, rUsedForFilter) 701 if err != nil { 702 return false, false, err 703 } 704 return matched, false, nil 705 } 706 707 func (j *leftOuterJoiner) tryToMatchOuters(outers chunk.Iterator, inner chunk.Event, chk *chunk.Chunk, outerEventStatus []outerEventStatusFlag) (_ []outerEventStatusFlag, err error) { 708 chkForJoin := chk 709 lUsed, rUsed := j.lUsed, j.rUsed 710 var lUsedForFilter, rUsedForFilter []int 711 if len(j.conditions) > 0 { 712 j.chk.Reset() 713 chkForJoin = j.chk 714 lUsed, rUsed = nil, nil 715 lUsedForFilter, rUsedForFilter = j.lUsed, j.rUsed 716 } 717 718 outer, numToAppend, cursor := outers.Current(), chk.RequiredEvents()-chk.NumEvents(), 0 719 for ; outer != outers.End() && cursor < numToAppend; outer, cursor = outers.Next(), cursor+1 { 720 j.makeJoinEventToChunk(chkForJoin, outer, inner, lUsed, rUsed) 721 } 722 err = outers.Error() 723 if err != nil { 724 return 725 } 726 outerEventStatus = outerEventStatus[:0] 727 for i := 0; i < cursor; i++ { 728 outerEventStatus = append(outerEventStatus, outerEventMatched) 729 } 730 if len(j.conditions) == 0 { 731 return outerEventStatus, nil 732 } 733 // reach here, chkForJoin is j.chk 734 return j.filterAndCheckOuterEventStatus(chkForJoin, chk, inner.Len(), outerEventStatus, lUsedForFilter, rUsedForFilter) 735 } 736 737 func (j *leftOuterJoiner) onMissMatch(_ bool, outer chunk.Event, chk *chunk.Chunk) { 738 lWide := chk.AppendEventByDefCausIdxs(outer, j.lUsed) 739 chk.AppendPartialEventByDefCausIdxs(lWide, j.defaultInner, j.rUsed) 740 } 741 742 func (j *leftOuterJoiner) Clone() joiner { 743 return &leftOuterJoiner{baseJoiner: j.baseJoiner.Clone()} 744 } 745 746 type rightOuterJoiner struct { 747 baseJoiner 748 } 749 750 // tryToMatchInners implements joiner interface. 751 func (j *rightOuterJoiner) tryToMatchInners(outer chunk.Event, inners chunk.Iterator, chk *chunk.Chunk) (matched bool, hasNull bool, err error) { 752 if inners.Len() == 0 { 753 return false, false, nil 754 } 755 chkForJoin := chk 756 lUsed, rUsed := j.lUsed, j.rUsed 757 var lUsedForFilter, rUsedForFilter []int 758 if len(j.conditions) > 0 { 759 j.chk.Reset() 760 chkForJoin = j.chk 761 lUsed, rUsed = nil, nil 762 lUsedForFilter, rUsedForFilter = j.lUsed, j.rUsed 763 } 764 765 numToAppend := chk.RequiredEvents() - chk.NumEvents() 766 for ; inners.Current() != inners.End() && numToAppend > 0; numToAppend-- { 767 j.makeJoinEventToChunk(chkForJoin, inners.Current(), outer, lUsed, rUsed) 768 inners.Next() 769 } 770 err = inners.Error() 771 if err != nil { 772 return false, false, err 773 } 774 if len(j.conditions) == 0 { 775 return true, false, nil 776 } 777 778 matched, err = j.filter(chkForJoin, chk, outer.Len(), lUsedForFilter, rUsedForFilter) 779 if err != nil { 780 return false, false, err 781 } 782 return matched, false, nil 783 } 784 785 func (j *rightOuterJoiner) tryToMatchOuters(outers chunk.Iterator, inner chunk.Event, chk *chunk.Chunk, outerEventStatus []outerEventStatusFlag) (_ []outerEventStatusFlag, err error) { 786 chkForJoin := chk 787 lUsed, rUsed := j.lUsed, j.rUsed 788 var lUsedForFilter, rUsedForFilter []int 789 if len(j.conditions) > 0 { 790 j.chk.Reset() 791 chkForJoin = j.chk 792 lUsed, rUsed = nil, nil 793 lUsedForFilter, rUsedForFilter = j.lUsed, j.rUsed 794 } 795 796 outer, numToAppend, cursor := outers.Current(), chk.RequiredEvents()-chk.NumEvents(), 0 797 for ; outer != outers.End() && cursor < numToAppend; outer, cursor = outers.Next(), cursor+1 { 798 j.makeJoinEventToChunk(chkForJoin, inner, outer, lUsed, rUsed) 799 } 800 801 outerEventStatus = outerEventStatus[:0] 802 for i := 0; i < cursor; i++ { 803 outerEventStatus = append(outerEventStatus, outerEventMatched) 804 } 805 if len(j.conditions) == 0 { 806 return outerEventStatus, nil 807 } 808 // reach here, chkForJoin is j.chk 809 return j.filterAndCheckOuterEventStatus(chkForJoin, chk, inner.Len(), outerEventStatus, lUsedForFilter, rUsedForFilter) 810 } 811 812 func (j *rightOuterJoiner) onMissMatch(_ bool, outer chunk.Event, chk *chunk.Chunk) { 813 lWide := chk.AppendEventByDefCausIdxs(j.defaultInner, j.lUsed) 814 chk.AppendPartialEventByDefCausIdxs(lWide, outer, j.rUsed) 815 } 816 817 func (j *rightOuterJoiner) Clone() joiner { 818 return &rightOuterJoiner{baseJoiner: j.baseJoiner.Clone()} 819 } 820 821 type innerJoiner struct { 822 baseJoiner 823 } 824 825 // tryToMatchInners implements joiner interface. 826 func (j *innerJoiner) tryToMatchInners(outer chunk.Event, inners chunk.Iterator, chk *chunk.Chunk) (matched bool, hasNull bool, err error) { 827 if inners.Len() == 0 { 828 return false, false, nil 829 } 830 chkForJoin := chk 831 lUsed, rUsed := j.lUsed, j.rUsed 832 var lUsedForFilter, rUsedForFilter []int 833 if len(j.conditions) > 0 { 834 j.chk.Reset() 835 chkForJoin = j.chk 836 lUsed, rUsed = nil, nil 837 lUsedForFilter, rUsedForFilter = j.lUsed, j.rUsed 838 } 839 840 inner, numToAppend := inners.Current(), chk.RequiredEvents()-chk.NumEvents() 841 for ; inner != inners.End() && numToAppend > 0; inner, numToAppend = inners.Next(), numToAppend-1 { 842 if j.outerIsRight { 843 j.makeJoinEventToChunk(chkForJoin, inner, outer, lUsed, rUsed) 844 } else { 845 j.makeJoinEventToChunk(chkForJoin, outer, inner, lUsed, rUsed) 846 } 847 } 848 err = inners.Error() 849 if err != nil { 850 return false, false, err 851 } 852 if len(j.conditions) == 0 { 853 return true, false, nil 854 } 855 856 // reach here, chkForJoin is j.chk 857 matched, err = j.filter(chkForJoin, chk, outer.Len(), lUsedForFilter, rUsedForFilter) 858 if err != nil { 859 return false, false, err 860 } 861 return matched, false, nil 862 } 863 864 func (j *innerJoiner) tryToMatchOuters(outers chunk.Iterator, inner chunk.Event, chk *chunk.Chunk, outerEventStatus []outerEventStatusFlag) (_ []outerEventStatusFlag, err error) { 865 chkForJoin := chk 866 lUsed, rUsed := j.lUsed, j.rUsed 867 var lUsedForFilter, rUsedForFilter []int 868 if len(j.conditions) > 0 { 869 j.chk.Reset() 870 chkForJoin = j.chk 871 lUsed, rUsed = nil, nil 872 lUsedForFilter, rUsedForFilter = j.lUsed, j.rUsed 873 } 874 875 outer, numToAppend, cursor := outers.Current(), chk.RequiredEvents()-chk.NumEvents(), 0 876 for ; outer != outers.End() && cursor < numToAppend; outer, cursor = outers.Next(), cursor+1 { 877 if j.outerIsRight { 878 j.makeJoinEventToChunk(chkForJoin, inner, outer, lUsed, rUsed) 879 } else { 880 j.makeJoinEventToChunk(chkForJoin, outer, inner, lUsed, rUsed) 881 } 882 } 883 err = outers.Error() 884 if err != nil { 885 return 886 } 887 outerEventStatus = outerEventStatus[:0] 888 for i := 0; i < cursor; i++ { 889 outerEventStatus = append(outerEventStatus, outerEventMatched) 890 } 891 if len(j.conditions) == 0 { 892 return outerEventStatus, nil 893 } 894 // reach here, chkForJoin is j.chk 895 return j.filterAndCheckOuterEventStatus(chkForJoin, chk, inner.Len(), outerEventStatus, lUsedForFilter, rUsedForFilter) 896 } 897 898 func (j *innerJoiner) onMissMatch(_ bool, outer chunk.Event, chk *chunk.Chunk) { 899 } 900 901 func (j *innerJoiner) Clone() joiner { 902 return &innerJoiner{baseJoiner: j.baseJoiner.Clone()} 903 }