vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/operators/vindex.go (about)

     1  /*
     2  Copyright 2022 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  	"vitess.io/vitess/go/vt/sqlparser"
    21  	"vitess.io/vitess/go/vt/vterrors"
    22  	"vitess.io/vitess/go/vt/vtgate/engine"
    23  	"vitess.io/vitess/go/vt/vtgate/planbuilder/operators/ops"
    24  	"vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext"
    25  	"vitess.io/vitess/go/vt/vtgate/semantics"
    26  	"vitess.io/vitess/go/vt/vtgate/vindexes"
    27  )
    28  
    29  type (
    30  	Vindex struct {
    31  		OpCode  engine.VindexOpcode
    32  		Table   VindexTable
    33  		Vindex  vindexes.Vindex
    34  		Solved  semantics.TableSet
    35  		Columns []*sqlparser.ColName
    36  		Value   sqlparser.Expr
    37  
    38  		noInputs
    39  	}
    40  
    41  	// VindexTable contains information about the vindex table we want to query
    42  	VindexTable struct {
    43  		TableID    semantics.TableSet
    44  		Alias      *sqlparser.AliasedTableExpr
    45  		Table      sqlparser.TableName
    46  		Predicates []sqlparser.Expr
    47  		VTable     *vindexes.Table
    48  	}
    49  )
    50  
    51  const VindexUnsupported = "WHERE clause for vindex function must be of the form id = <val> or id in(<val>,...)"
    52  
    53  // Introduces implements the Operator interface
    54  func (v *Vindex) Introduces() semantics.TableSet {
    55  	return v.Solved
    56  }
    57  
    58  // IPhysical implements the PhysicalOperator interface
    59  func (v *Vindex) IPhysical() {}
    60  
    61  // Clone implements the Operator interface
    62  func (v *Vindex) Clone([]ops.Operator) ops.Operator {
    63  	clone := *v
    64  	return &clone
    65  }
    66  
    67  var _ ops.PhysicalOperator = (*Vindex)(nil)
    68  
    69  func (v *Vindex) AddColumn(_ *plancontext.PlanningContext, expr sqlparser.Expr) (int, error) {
    70  	return addColumn(v, expr)
    71  }
    72  
    73  func (v *Vindex) GetColumns() []*sqlparser.ColName {
    74  	return v.Columns
    75  }
    76  func (v *Vindex) AddCol(col *sqlparser.ColName) {
    77  	v.Columns = append(v.Columns, col)
    78  }
    79  
    80  // checkValid implements the Operator interface
    81  func (v *Vindex) CheckValid() error {
    82  	if len(v.Table.Predicates) == 0 {
    83  		return vterrors.VT12001(VindexUnsupported + " (where clause missing)")
    84  	}
    85  
    86  	return nil
    87  }
    88  
    89  func (v *Vindex) AddPredicate(ctx *plancontext.PlanningContext, expr sqlparser.Expr) (ops.Operator, error) {
    90  	for _, e := range sqlparser.SplitAndExpression(nil, expr) {
    91  		deps := ctx.SemTable.RecursiveDeps(e)
    92  		if deps.NumberOfTables() > 1 {
    93  			return nil, vterrors.VT12001(VindexUnsupported + " (multiple tables involved)")
    94  		}
    95  		// check if we already have a predicate
    96  		if v.OpCode != engine.VindexNone {
    97  			return nil, vterrors.VT12001(VindexUnsupported + " (multiple filters)")
    98  		}
    99  
   100  		// check LHS
   101  		comparison, ok := e.(*sqlparser.ComparisonExpr)
   102  		if !ok {
   103  			return nil, vterrors.VT12001(VindexUnsupported + " (not a comparison)")
   104  		}
   105  		if comparison.Operator != sqlparser.EqualOp && comparison.Operator != sqlparser.InOp {
   106  			return nil, vterrors.VT12001(VindexUnsupported + " (not equality)")
   107  		}
   108  		colname, ok := comparison.Left.(*sqlparser.ColName)
   109  		if !ok {
   110  			return nil, vterrors.VT12001(VindexUnsupported + " (lhs is not a column)")
   111  		}
   112  		if !colname.Name.EqualString("id") {
   113  			return nil, vterrors.VT12001(VindexUnsupported + " (lhs is not id)")
   114  		}
   115  
   116  		// check RHS
   117  		var err error
   118  		if sqlparser.IsValue(comparison.Right) || sqlparser.IsSimpleTuple(comparison.Right) {
   119  			v.Value = comparison.Right
   120  		} else {
   121  			return nil, vterrors.VT12001(VindexUnsupported + " (rhs is not a value)")
   122  		}
   123  		if err != nil {
   124  			return nil, vterrors.VT12001(VindexUnsupported+": %v", err)
   125  		}
   126  		v.OpCode = engine.VindexMap
   127  		v.Table.Predicates = append(v.Table.Predicates, e)
   128  	}
   129  	return v, nil
   130  }
   131  
   132  // TablesUsed implements the Operator interface.
   133  // It is not keyspace-qualified.
   134  func (v *Vindex) TablesUsed() []string {
   135  	return []string{v.Table.Table.Name.String()}
   136  }