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 }