vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/operators/apply_join.go (about)

     1  /*
     2  Copyright 2021 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package operators
    18  
    19  import (
    20  	"golang.org/x/exp/maps"
    21  	"golang.org/x/exp/slices"
    22  
    23  	"vitess.io/vitess/go/vt/vtgate/planbuilder/operators/ops"
    24  
    25  	"vitess.io/vitess/go/vt/sqlparser"
    26  	"vitess.io/vitess/go/vt/vterrors"
    27  	"vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext"
    28  )
    29  
    30  // ApplyJoin is a nested loop join - for each row on the LHS,
    31  // we'll execute the plan on the RHS, feeding data from left to right
    32  type ApplyJoin struct {
    33  	LHS, RHS ops.Operator
    34  
    35  	// Columns stores the column indexes of the columns coming from the left and right side
    36  	// negative value comes from LHS and positive from RHS
    37  	Columns []int
    38  
    39  	// ColumnsAST keeps track of what AST expression is represented in the Columns array
    40  	ColumnsAST []sqlparser.Expr
    41  
    42  	// Vars are the arguments that need to be copied from the LHS to the RHS
    43  	Vars map[string]int
    44  
    45  	// LeftJoin will be true in the case of an outer join
    46  	LeftJoin bool
    47  
    48  	// JoinCols are the columns from the LHS used for the join.
    49  	// These are the same columns pushed on the LHS that are now used in the Vars field
    50  	LHSColumns []*sqlparser.ColName
    51  
    52  	Predicate sqlparser.Expr
    53  }
    54  
    55  var _ ops.PhysicalOperator = (*ApplyJoin)(nil)
    56  
    57  func NewApplyJoin(lhs, rhs ops.Operator, predicate sqlparser.Expr, leftOuterJoin bool) *ApplyJoin {
    58  	return &ApplyJoin{
    59  		LHS:       lhs,
    60  		RHS:       rhs,
    61  		Vars:      map[string]int{},
    62  		Predicate: predicate,
    63  		LeftJoin:  leftOuterJoin,
    64  	}
    65  }
    66  
    67  // IPhysical implements the PhysicalOperator interface
    68  func (a *ApplyJoin) IPhysical() {}
    69  
    70  // Clone implements the Operator interface
    71  func (a *ApplyJoin) Clone(inputs []ops.Operator) ops.Operator {
    72  	return &ApplyJoin{
    73  		LHS:        inputs[0],
    74  		RHS:        inputs[1],
    75  		Columns:    slices.Clone(a.Columns),
    76  		ColumnsAST: slices.Clone(a.ColumnsAST),
    77  		Vars:       maps.Clone(a.Vars),
    78  		LeftJoin:   a.LeftJoin,
    79  		Predicate:  sqlparser.CloneExpr(a.Predicate),
    80  		LHSColumns: slices.Clone(a.LHSColumns),
    81  	}
    82  }
    83  
    84  func (a *ApplyJoin) AddPredicate(ctx *plancontext.PlanningContext, expr sqlparser.Expr) (ops.Operator, error) {
    85  	return AddPredicate(a, ctx, expr, false, newFilter)
    86  }
    87  
    88  // Inputs implements the Operator interface
    89  func (a *ApplyJoin) Inputs() []ops.Operator {
    90  	return []ops.Operator{a.LHS, a.RHS}
    91  }
    92  
    93  var _ JoinOp = (*ApplyJoin)(nil)
    94  
    95  func (a *ApplyJoin) GetLHS() ops.Operator {
    96  	return a.LHS
    97  }
    98  
    99  func (a *ApplyJoin) GetRHS() ops.Operator {
   100  	return a.RHS
   101  }
   102  
   103  func (a *ApplyJoin) SetLHS(operator ops.Operator) {
   104  	a.LHS = operator
   105  }
   106  
   107  func (a *ApplyJoin) SetRHS(operator ops.Operator) {
   108  	a.RHS = operator
   109  }
   110  
   111  func (a *ApplyJoin) MakeInner() {
   112  	a.LeftJoin = false
   113  }
   114  
   115  func (a *ApplyJoin) IsInner() bool {
   116  	return !a.LeftJoin
   117  }
   118  
   119  func (a *ApplyJoin) AddJoinPredicate(ctx *plancontext.PlanningContext, expr sqlparser.Expr) error {
   120  	bvName, cols, predicate, err := BreakExpressionInLHSandRHS(ctx, expr, TableID(a.LHS))
   121  	if err != nil {
   122  		return err
   123  	}
   124  	for i, col := range cols {
   125  		offset, err := a.LHS.AddColumn(ctx, col)
   126  		if err != nil {
   127  			return err
   128  		}
   129  		a.Vars[bvName[i]] = offset
   130  	}
   131  	a.LHSColumns = append(a.LHSColumns, cols...)
   132  
   133  	rhs, err := a.RHS.AddPredicate(ctx, predicate)
   134  	if err != nil {
   135  		return err
   136  	}
   137  	a.RHS = rhs
   138  
   139  	a.Predicate = ctx.SemTable.AndExpressions(expr, a.Predicate)
   140  	return nil
   141  }
   142  
   143  func (a *ApplyJoin) AddColumn(ctx *plancontext.PlanningContext, expr sqlparser.Expr) (int, error) {
   144  	// first check if we already are passing through this expression
   145  	for i, existing := range a.ColumnsAST {
   146  		if ctx.SemTable.EqualsExpr(existing, expr) {
   147  			return i, nil
   148  		}
   149  	}
   150  
   151  	lhs := TableID(a.LHS)
   152  	rhs := TableID(a.RHS)
   153  	both := lhs.Merge(rhs)
   154  	deps := ctx.SemTable.RecursiveDeps(expr)
   155  
   156  	// if we get here, it's a new expression we are dealing with.
   157  	// We need to decide if we can push it all on either side,
   158  	// or if we have to break the expression into left and right parts
   159  	switch {
   160  	case deps.IsSolvedBy(lhs):
   161  		offset, err := a.LHS.AddColumn(ctx, expr)
   162  		if err != nil {
   163  			return 0, err
   164  		}
   165  		a.Columns = append(a.Columns, -offset-1)
   166  	case deps.IsSolvedBy(both):
   167  		bvNames, lhsExprs, rhsExpr, err := BreakExpressionInLHSandRHS(ctx, expr, lhs)
   168  		if err != nil {
   169  			return 0, err
   170  		}
   171  		for i, lhsExpr := range lhsExprs {
   172  			offset, err := a.LHS.AddColumn(ctx, lhsExpr)
   173  			if err != nil {
   174  				return 0, err
   175  			}
   176  			a.Vars[bvNames[i]] = offset
   177  		}
   178  		expr = rhsExpr
   179  		fallthrough // now we just pass the rest to the RHS of the join
   180  	case deps.IsSolvedBy(rhs):
   181  		offset, err := a.RHS.AddColumn(ctx, expr)
   182  		if err != nil {
   183  			return 0, err
   184  		}
   185  		a.Columns = append(a.Columns, offset+1)
   186  	default:
   187  		return 0, vterrors.VT13002(sqlparser.String(expr))
   188  	}
   189  
   190  	// the expression wasn't already there - let's add it
   191  	a.ColumnsAST = append(a.ColumnsAST, expr)
   192  	return len(a.Columns) - 1, nil
   193  }