vitess.io/vitess@v0.16.2/go/vt/vtgate/semantics/derived_table.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 semantics
    18  
    19  import (
    20  	"strings"
    21  
    22  	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
    23  	"vitess.io/vitess/go/vt/sqlparser"
    24  	"vitess.io/vitess/go/vt/vterrors"
    25  	"vitess.io/vitess/go/vt/vtgate/vindexes"
    26  )
    27  
    28  // DerivedTable contains the information about the projection, tables involved in derived table.
    29  type DerivedTable struct {
    30  	tableName       string
    31  	ASTNode         *sqlparser.AliasedTableExpr
    32  	columnNames     []string
    33  	cols            []sqlparser.Expr
    34  	tables          TableSet
    35  	isAuthoritative bool
    36  }
    37  
    38  var _ TableInfo = (*DerivedTable)(nil)
    39  
    40  func createDerivedTableForExpressions(expressions sqlparser.SelectExprs, cols sqlparser.Columns, tables []TableInfo, org originable) *DerivedTable {
    41  	vTbl := &DerivedTable{isAuthoritative: true}
    42  	for i, selectExpr := range expressions {
    43  		switch expr := selectExpr.(type) {
    44  		case *sqlparser.AliasedExpr:
    45  			vTbl.cols = append(vTbl.cols, expr.Expr)
    46  			if len(cols) > 0 {
    47  				vTbl.columnNames = append(vTbl.columnNames, cols[i].String())
    48  			} else if expr.As.IsEmpty() {
    49  				switch expr := expr.Expr.(type) {
    50  				case *sqlparser.ColName:
    51  					// for projections, we strip out the qualifier and keep only the column name
    52  					vTbl.columnNames = append(vTbl.columnNames, expr.Name.String())
    53  				default:
    54  					vTbl.columnNames = append(vTbl.columnNames, sqlparser.String(expr))
    55  				}
    56  			} else {
    57  				vTbl.columnNames = append(vTbl.columnNames, expr.As.String())
    58  			}
    59  		case *sqlparser.StarExpr:
    60  			for _, table := range tables {
    61  				vTbl.tables = vTbl.tables.Merge(table.getTableSet(org))
    62  				if !table.authoritative() {
    63  					vTbl.isAuthoritative = false
    64  				}
    65  			}
    66  		}
    67  	}
    68  	return vTbl
    69  }
    70  
    71  // dependencies implements the TableInfo interface
    72  func (dt *DerivedTable) dependencies(colName string, org originable) (dependencies, error) {
    73  	directDeps := org.tableSetFor(dt.ASTNode)
    74  	for i, name := range dt.columnNames {
    75  		if !strings.EqualFold(name, colName) {
    76  			continue
    77  		}
    78  		_, recursiveDeps, qt := org.depsForExpr(dt.cols[i])
    79  
    80  		return createCertain(directDeps, recursiveDeps, qt), nil
    81  	}
    82  
    83  	if !dt.hasStar() {
    84  		return &nothing{}, nil
    85  	}
    86  
    87  	return createUncertain(directDeps, dt.tables), nil
    88  }
    89  
    90  // IsInfSchema implements the TableInfo interface
    91  func (dt *DerivedTable) IsInfSchema() bool {
    92  	return false
    93  }
    94  
    95  func (dt *DerivedTable) matches(name sqlparser.TableName) bool {
    96  	return dt.tableName == name.Name.String() && name.Qualifier.IsEmpty()
    97  }
    98  
    99  func (dt *DerivedTable) authoritative() bool {
   100  	return dt.isAuthoritative
   101  }
   102  
   103  // Name implements the TableInfo interface
   104  func (dt *DerivedTable) Name() (sqlparser.TableName, error) {
   105  	return dt.ASTNode.TableName()
   106  }
   107  
   108  func (dt *DerivedTable) getExpr() *sqlparser.AliasedTableExpr {
   109  	return dt.ASTNode
   110  }
   111  
   112  // GetVindexTable implements the TableInfo interface
   113  func (dt *DerivedTable) GetVindexTable() *vindexes.Table {
   114  	return nil
   115  }
   116  
   117  func (dt *DerivedTable) getColumns() []ColumnInfo {
   118  	cols := make([]ColumnInfo, 0, len(dt.columnNames))
   119  	for _, col := range dt.columnNames {
   120  		cols = append(cols, ColumnInfo{
   121  			Name: col,
   122  		})
   123  	}
   124  	return cols
   125  }
   126  
   127  func (dt *DerivedTable) hasStar() bool {
   128  	return dt.tables.NonEmpty()
   129  }
   130  
   131  // GetTables implements the TableInfo interface
   132  func (dt *DerivedTable) getTableSet(_ originable) TableSet {
   133  	return dt.tables
   134  }
   135  
   136  // GetExprFor implements the TableInfo interface
   137  func (dt *DerivedTable) getExprFor(s string) (sqlparser.Expr, error) {
   138  	for i, colName := range dt.columnNames {
   139  		if colName == s {
   140  			return dt.cols[i], nil
   141  		}
   142  	}
   143  	return nil, vterrors.NewErrorf(vtrpcpb.Code_NOT_FOUND, vterrors.BadFieldError, "Unknown column '%s' in 'field list'", s)
   144  }
   145  
   146  func (dt *DerivedTable) checkForDuplicates() error {
   147  	for i, name := range dt.columnNames {
   148  		for j, name2 := range dt.columnNames {
   149  			if i == j {
   150  				continue
   151  			}
   152  			if name == name2 {
   153  				return vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.DupFieldName, "Duplicate column name '%s'", name)
   154  			}
   155  		}
   156  	}
   157  	return nil
   158  }