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  // -------------------------------------------------------------------------