vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/simple_projection.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  )
    26  
    27  var _ logicalPlan = (*simpleProjection)(nil)
    28  
    29  // simpleProjection is used for wrapping a derived table.
    30  // This primitive wraps any derived table that results
    31  // in something that's not a route. It builds a
    32  // 'table' for the derived table allowing higher level
    33  // constructs to reference its columns. If a derived table
    34  // results in a route primitive, we instead build
    35  // a new route that keeps the subquery in the FROM
    36  // clause, because a route is more versatile than
    37  // a simpleProjection.
    38  // this should not be used by the gen4 planner
    39  type simpleProjection struct {
    40  	logicalPlanCommon
    41  	resultColumns []*resultColumn
    42  	eSimpleProj   *engine.SimpleProjection
    43  }
    44  
    45  // newSimpleProjection builds a new simpleProjection.
    46  func newSimpleProjection(alias sqlparser.IdentifierCS, plan logicalPlan) (*simpleProjection, *symtab, error) {
    47  	sq := &simpleProjection{
    48  		logicalPlanCommon: newBuilderCommon(plan),
    49  		eSimpleProj:       &engine.SimpleProjection{},
    50  	}
    51  
    52  	// Create a 'table' that represents the derived table.
    53  	t := &table{
    54  		alias:  sqlparser.TableName{Name: alias},
    55  		origin: sq,
    56  	}
    57  
    58  	// Create column symbols based on the result column names.
    59  	for _, rc := range plan.ResultColumns() {
    60  		if _, ok := t.columns[rc.alias.Lowered()]; ok {
    61  			return nil, nil, vterrors.VT12001(fmt.Sprintf("duplicate column names in subquery: %s", sqlparser.String(rc.alias)))
    62  		}
    63  		t.addColumn(rc.alias, &column{origin: sq})
    64  	}
    65  	t.isAuthoritative = true
    66  	st := newSymtab()
    67  	// AddTable will not fail because symtab is empty.
    68  	_ = st.AddTable(t)
    69  	return sq, st, nil
    70  }
    71  
    72  // Primitive implements the logicalPlan interface
    73  func (sq *simpleProjection) Primitive() engine.Primitive {
    74  	sq.eSimpleProj.Input = sq.input.Primitive()
    75  	return sq.eSimpleProj
    76  }
    77  
    78  // ResultColumns implements the logicalPlan interface
    79  func (sq *simpleProjection) ResultColumns() []*resultColumn {
    80  	return sq.resultColumns
    81  }
    82  
    83  // SupplyCol implements the logicalPlan interface
    84  func (sq *simpleProjection) SupplyCol(col *sqlparser.ColName) (rc *resultColumn, colNumber int) {
    85  	c := col.Metadata.(*column)
    86  	for i, rc := range sq.resultColumns {
    87  		if rc.column == c {
    88  			return rc, i
    89  		}
    90  	}
    91  
    92  	// columns that reference subqueries will have their colNumber set.
    93  	// Let's use it here.
    94  	sq.eSimpleProj.Cols = append(sq.eSimpleProj.Cols, c.colNumber)
    95  	sq.resultColumns = append(sq.resultColumns, &resultColumn{column: c})
    96  	return rc, len(sq.resultColumns) - 1
    97  }
    98  
    99  // OutputColumns implements the logicalPlan interface
   100  func (sq *simpleProjection) OutputColumns() []sqlparser.SelectExpr {
   101  	exprs := make([]sqlparser.SelectExpr, 0, len(sq.eSimpleProj.Cols))
   102  	outputCols := sq.input.OutputColumns()
   103  	for _, colID := range sq.eSimpleProj.Cols {
   104  		exprs = append(exprs, outputCols[colID])
   105  	}
   106  	return exprs
   107  }