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  }