vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/logical_plan.go (about) 1 /* 2 Copyright 2019 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 planbuilder 18 19 import ( 20 "fmt" 21 22 "vitess.io/vitess/go/vt/sqlparser" 23 "vitess.io/vitess/go/vt/vterrors" 24 "vitess.io/vitess/go/vt/vtgate/engine" 25 "vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext" 26 "vitess.io/vitess/go/vt/vtgate/semantics" 27 ) 28 29 // logicalPlan defines the interface that a primitive must 30 // satisfy. 31 type logicalPlan interface { 32 // Order is the execution order of the primitive. If there are subprimitives, 33 // the order is one above the order of the subprimitives. 34 // This is because the primitive executes its subprimitives first and 35 // processes their results to generate its own values. 36 // Please copy code from an existing primitive to define this function. 37 Order() int 38 39 // ResultColumns returns the list of result columns the 40 // primitive returns. 41 // Please copy code from an existing primitive to define this function. 42 ResultColumns() []*resultColumn 43 44 // Reorder reassigns order for the primitive and its sub-primitives. 45 // The input is the order of the previous primitive that should 46 // execute before this one. 47 Reorder(int) 48 49 // Wireup performs the wire-up work. Nodes should be traversed 50 // from right to left because the rhs nodes can request vars from 51 // the lhs nodes. 52 Wireup(lp logicalPlan, jt *jointab) error 53 54 // WireupGen4 does the wire up work for the Gen4 planner 55 WireupGen4(*plancontext.PlanningContext) error 56 57 // SupplyVar finds the common root between from and to. If it's 58 // the common root, it supplies the requested var to the rhs tree. 59 // If the primitive already has the column in its list, it should 60 // just supply it to the 'to' node. Otherwise, it should request 61 // for it by calling SupplyCol on the 'from' sub-tree to request the 62 // column, and then supply it to the 'to' node. 63 SupplyVar(from, to int, col *sqlparser.ColName, varname string) 64 65 // SupplyCol is meant to be used for the wire-up process. This function 66 // changes the primitive to supply the requested column and returns 67 // the resultColumn and column number of the result. SupplyCol 68 // is different from PushSelect because it may reuse an existing 69 // resultColumn, whereas PushSelect guarantees the addition of a new 70 // result column and returns a distinct symbol for it. 71 SupplyCol(col *sqlparser.ColName) (rc *resultColumn, colNumber int) 72 73 // SupplyWeightString must supply a weight_string expression of the 74 // specified column. It returns an error if we cannot supply a weight column for it. 75 SupplyWeightString(colNumber int, alsoAddToGroupBy bool) (weightcolNumber int, err error) 76 77 // Primitive returns the underlying primitive. 78 // This function should only be called after Wireup is finished. 79 Primitive() engine.Primitive 80 81 // Inputs are the children of this plan 82 Inputs() []logicalPlan 83 84 // Rewrite replaces the inputs of this plan with the ones provided 85 Rewrite(inputs ...logicalPlan) error 86 87 // ContainsTables keeps track which query tables are being solved by this logical plan 88 // This is only applicable for plans that have been built with the Gen4 planner 89 ContainsTables() semantics.TableSet 90 91 // OutputColumns shows the columns that this plan will produce 92 OutputColumns() []sqlparser.SelectExpr 93 } 94 95 // gen4Plan implements a few methods from logicalPlan that are unused by Gen4. 96 type gen4Plan struct{} 97 98 // Order implements the logicalPlan interface 99 func (*gen4Plan) Order() int { 100 panic("[BUG]: should not be called. This is a Gen4 primitive") 101 } 102 103 // ResultColumns implements the logicalPlan interface 104 func (*gen4Plan) ResultColumns() []*resultColumn { 105 panic("[BUG]: should not be called. This is a Gen4 primitive") 106 } 107 108 // Reorder implements the logicalPlan interface 109 func (*gen4Plan) Reorder(int) { 110 panic("[BUG]: should not be called. This is a Gen4 primitive") 111 } 112 113 // Wireup implements the logicalPlan interface 114 func (*gen4Plan) Wireup(logicalPlan, *jointab) error { 115 panic("[BUG]: should not be called. This is a Gen4 primitive") 116 } 117 118 // SupplyVar implements the logicalPlan interface 119 func (*gen4Plan) SupplyVar(int, int, *sqlparser.ColName, string) { 120 panic("[BUG]: should not be called. This is a Gen4 primitive") 121 } 122 123 // SupplyCol implements the logicalPlan interface 124 func (*gen4Plan) SupplyCol(*sqlparser.ColName) (rc *resultColumn, colNumber int) { 125 panic("[BUG]: should not be called. This is a Gen4 primitive") 126 } 127 128 // SupplyWeightString implements the logicalPlan interface 129 func (*gen4Plan) SupplyWeightString(int, bool) (weightcolNumber int, err error) { 130 panic("[BUG]: should not be called. This is a Gen4 primitive") 131 } 132 133 // v3Plan implements methods that are only used by gen4 134 type v3Plan struct{} 135 136 func (*v3Plan) WireupGen4(*plancontext.PlanningContext) error { 137 panic("[BUG]: should not be called. This is a V3 primitive") 138 } 139 140 func (*v3Plan) ContainsTables() semantics.TableSet { 141 panic("[BUG]: should not be called. This is a V3 primitive") 142 } 143 144 func (*v3Plan) OutputColumns() []sqlparser.SelectExpr { 145 panic("[BUG]: should not be called. This is a V3 primitive") 146 } 147 148 type planVisitor func(logicalPlan) (bool, logicalPlan, error) 149 150 func visit(node logicalPlan, visitor planVisitor) (logicalPlan, error) { 151 if visitor != nil { 152 kontinue, newNode, err := visitor(node) 153 if err != nil { 154 return nil, err 155 } 156 if !kontinue { 157 return newNode, nil 158 } 159 node = newNode 160 } 161 inputs := node.Inputs() 162 rewrite := false 163 for i, input := range inputs { 164 newInput, err := visit(input, visitor) 165 if err != nil { 166 return nil, err 167 } 168 if newInput != input { 169 rewrite = true 170 } 171 inputs[i] = newInput 172 } 173 if rewrite { 174 err := node.Rewrite(inputs...) 175 if err != nil { 176 return nil, err 177 } 178 } 179 180 return node, nil 181 } 182 183 // first returns the first logical plan of the tree, 184 // which is usually the left most leaf. 185 func first(input logicalPlan) logicalPlan { 186 inputs := input.Inputs() 187 if len(inputs) == 0 { 188 return input 189 } 190 return first(inputs[0]) 191 } 192 193 // ------------------------------------------------------------------------- 194 195 // logicalPlanCommon implements some common functionality of builders. 196 // Make sure to override in case behavior needs to be changed. 197 type logicalPlanCommon struct { 198 order int 199 input logicalPlan 200 } 201 202 func newBuilderCommon(input logicalPlan) logicalPlanCommon { 203 return logicalPlanCommon{input: input} 204 } 205 206 func (bc *logicalPlanCommon) Order() int { 207 return bc.order 208 } 209 210 func (bc *logicalPlanCommon) Reorder(order int) { 211 bc.input.Reorder(order) 212 bc.order = bc.input.Order() + 1 213 } 214 215 func (bc *logicalPlanCommon) ResultColumns() []*resultColumn { 216 return bc.input.ResultColumns() 217 } 218 219 func (bc *logicalPlanCommon) Wireup(plan logicalPlan, jt *jointab) error { 220 return bc.input.Wireup(plan, jt) 221 } 222 223 func (bc *logicalPlanCommon) WireupGen4(ctx *plancontext.PlanningContext) error { 224 return bc.input.WireupGen4(ctx) 225 } 226 227 func (bc *logicalPlanCommon) SupplyVar(from, to int, col *sqlparser.ColName, varname string) { 228 bc.input.SupplyVar(from, to, col, varname) 229 } 230 231 func (bc *logicalPlanCommon) SupplyCol(col *sqlparser.ColName) (rc *resultColumn, colNumber int) { 232 return bc.input.SupplyCol(col) 233 } 234 235 func (bc *logicalPlanCommon) SupplyWeightString(colNumber int, alsoAddToGroupBy bool) (weightcolNumber int, err error) { 236 return bc.input.SupplyWeightString(colNumber, alsoAddToGroupBy) 237 } 238 239 // Rewrite implements the logicalPlan interface 240 func (bc *logicalPlanCommon) Rewrite(inputs ...logicalPlan) error { 241 if len(inputs) != 1 { 242 return vterrors.VT13001(fmt.Sprintf("builderCommon: wrong number of inputs, got: %d, expect: 1", len(inputs))) 243 } 244 bc.input = inputs[0] 245 return nil 246 } 247 248 // Inputs implements the logicalPlan interface 249 func (bc *logicalPlanCommon) Inputs() []logicalPlan { 250 return []logicalPlan{bc.input} 251 } 252 253 // ContainsTables implements the logicalPlan interface 254 func (bc *logicalPlanCommon) ContainsTables() semantics.TableSet { 255 return bc.input.ContainsTables() 256 } 257 258 // OutputColumns implements the logicalPlan interface 259 func (bc *logicalPlanCommon) OutputColumns() []sqlparser.SelectExpr { 260 return bc.input.OutputColumns() 261 } 262 263 // ------------------------------------------------------------------------- 264 265 // resultsBuilder is a superset of logicalPlanCommon. It also handles 266 // resultsColumn functionality. 267 type resultsBuilder struct { 268 logicalPlanCommon 269 resultColumns []*resultColumn 270 weightStrings map[*resultColumn]int 271 truncater truncater 272 } 273 274 func newResultsBuilder(input logicalPlan, truncater truncater) resultsBuilder { 275 return resultsBuilder{ 276 logicalPlanCommon: newBuilderCommon(input), 277 resultColumns: input.ResultColumns(), 278 weightStrings: make(map[*resultColumn]int), 279 truncater: truncater, 280 } 281 } 282 283 func (rsb *resultsBuilder) ResultColumns() []*resultColumn { 284 return rsb.resultColumns 285 } 286 287 // SupplyCol is currently unreachable because the builders using resultsBuilder 288 // are currently above a join, which is the only logicalPlan that uses it for now. 289 // This can change if we start supporting correlated subqueries. 290 func (rsb *resultsBuilder) SupplyCol(col *sqlparser.ColName) (rc *resultColumn, colNumber int) { 291 c := col.Metadata.(*column) 292 for i, rc := range rsb.resultColumns { 293 if rc.column == c { 294 return rc, i 295 } 296 } 297 rc, colNumber = rsb.input.SupplyCol(col) 298 if colNumber < len(rsb.resultColumns) { 299 return rc, colNumber 300 } 301 // Add result columns from input until colNumber is reached. 302 for colNumber >= len(rsb.resultColumns) { 303 rsb.resultColumns = append(rsb.resultColumns, rsb.input.ResultColumns()[len(rsb.resultColumns)]) 304 } 305 rsb.truncater.SetTruncateColumnCount(len(rsb.resultColumns)) 306 return rc, colNumber 307 } 308 309 func (rsb *resultsBuilder) SupplyWeightString(colNumber int, alsoAddToGroupBy bool) (weightcolNumber int, err error) { 310 rc := rsb.resultColumns[colNumber] 311 var ok bool 312 weightcolNumber, ok = rsb.weightStrings[rc] 313 if !alsoAddToGroupBy && ok { 314 return weightcolNumber, nil 315 } 316 weightcolNumber, err = rsb.input.SupplyWeightString(colNumber, alsoAddToGroupBy) 317 if err != nil { 318 return 0, nil 319 } 320 rsb.weightStrings[rc] = weightcolNumber 321 if weightcolNumber < len(rsb.resultColumns) { 322 return weightcolNumber, nil 323 } 324 // Add result columns from input until weightcolNumber is reached. 325 for weightcolNumber >= len(rsb.resultColumns) { 326 rsb.resultColumns = append(rsb.resultColumns, rsb.input.ResultColumns()[len(rsb.resultColumns)]) 327 } 328 rsb.truncater.SetTruncateColumnCount(len(rsb.resultColumns)) 329 return weightcolNumber, nil 330 } 331 332 // -------------------------------------------------------------------------