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 }