vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/operators/dml_planning.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 "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/evalengine" 26 "vitess.io/vitess/go/vt/vtgate/semantics" 27 "vitess.io/vitess/go/vt/vtgate/vindexes" 28 ) 29 30 // getVindexInformation returns the vindex and VindexPlusPredicates for the DML, 31 // If it cannot find a unique vindex match, it returns an error. 32 func getVindexInformation( 33 id semantics.TableSet, 34 predicates []sqlparser.Expr, 35 table *vindexes.Table, 36 ) (*vindexes.ColumnVindex, []*VindexPlusPredicates, error) { 37 // Check that we have a primary vindex which is valid 38 if len(table.ColumnVindexes) == 0 || !table.ColumnVindexes[0].IsUnique() { 39 return nil, nil, vterrors.VT09001(table.Name) 40 } 41 primaryVindex := table.ColumnVindexes[0] 42 if len(predicates) == 0 { 43 return primaryVindex, nil, nil 44 } 45 46 var vindexesAndPredicates []*VindexPlusPredicates 47 for _, colVindex := range table.Ordered { 48 if lu, isLu := colVindex.Vindex.(vindexes.LookupBackfill); isLu && lu.IsBackfilling() { 49 // Checking if the Vindex is currently backfilling or not, if it isn't we can read from the vindex table 50 // and we will be able to do a delete equal. Otherwise, we continue to look for next best vindex. 51 continue 52 } 53 54 vindexesAndPredicates = append(vindexesAndPredicates, &VindexPlusPredicates{ 55 ColVindex: colVindex, 56 TableID: id, 57 }) 58 } 59 return primaryVindex, vindexesAndPredicates, nil 60 } 61 62 // buildChangedVindexesValues adds to the plan all the lookup vindexes that are changing. 63 // Updates can only be performed to secondary lookup vindexes with no complex expressions 64 // in the set clause. 65 func buildChangedVindexesValues(update *sqlparser.Update, table *vindexes.Table, ksidCols []sqlparser.IdentifierCI) (map[string]*engine.VindexValues, string, error) { 66 changedVindexes := make(map[string]*engine.VindexValues) 67 buf, offset := initialQuery(ksidCols, table) 68 for i, vindex := range table.ColumnVindexes { 69 vindexValueMap := make(map[string]evalengine.Expr) 70 first := true 71 for _, vcol := range vindex.Columns { 72 // Searching in order of columns in colvindex. 73 found := false 74 for _, assignment := range update.Exprs { 75 if !vcol.Equal(assignment.Name.Name) { 76 continue 77 } 78 if found { 79 return nil, "", vterrors.VT03015(assignment.Name.Name) 80 } 81 found = true 82 pv, err := extractValueFromUpdate(assignment) 83 if err != nil { 84 return nil, "", err 85 } 86 vindexValueMap[vcol.String()] = pv 87 if first { 88 buf.Myprintf(", %v", assignment) 89 first = false 90 } else { 91 buf.Myprintf(" and %v", assignment) 92 } 93 } 94 } 95 if len(vindexValueMap) == 0 { 96 // Vindex not changing, continue 97 continue 98 } 99 100 if update.Limit != nil && len(update.OrderBy) == 0 { 101 return nil, "", vterrors.VT12001(fmt.Sprintf("you need to provide the ORDER BY clause when using LIMIT; invalid update on vindex: %v", vindex.Name)) 102 } 103 if i == 0 { 104 return nil, "", vterrors.VT12001(fmt.Sprintf("you cannot UPDATE primary vindex columns; invalid update on vindex: %v", vindex.Name)) 105 } 106 if _, ok := vindex.Vindex.(vindexes.Lookup); !ok { 107 return nil, "", vterrors.VT12001(fmt.Sprintf("you can only UPDATE lookup vindexes; invalid update on vindex: %v", vindex.Name)) 108 } 109 changedVindexes[vindex.Name] = &engine.VindexValues{ 110 PvMap: vindexValueMap, 111 Offset: offset, 112 } 113 offset++ 114 } 115 if len(changedVindexes) == 0 { 116 return nil, "", nil 117 } 118 // generate rest of the owned vindex query. 119 aTblExpr, ok := update.TableExprs[0].(*sqlparser.AliasedTableExpr) 120 if !ok { 121 return nil, "", vterrors.VT12001("UPDATE on complex table expression") 122 } 123 tblExpr := &sqlparser.AliasedTableExpr{Expr: sqlparser.TableName{Name: table.Name}, As: aTblExpr.As} 124 buf.Myprintf(" from %v%v%v%v for update", tblExpr, update.Where, update.OrderBy, update.Limit) 125 return changedVindexes, buf.String(), nil 126 } 127 128 func initialQuery(ksidCols []sqlparser.IdentifierCI, table *vindexes.Table) (*sqlparser.TrackedBuffer, int) { 129 buf := sqlparser.NewTrackedBuffer(nil) 130 offset := 0 131 for _, col := range ksidCols { 132 if offset == 0 { 133 buf.Myprintf("select %v", col) 134 } else { 135 buf.Myprintf(", %v", col) 136 } 137 offset++ 138 } 139 for _, cv := range table.Owned { 140 for _, column := range cv.Columns { 141 buf.Myprintf(", %v", column) 142 offset++ 143 } 144 } 145 return buf, offset 146 } 147 148 // extractValueFromUpdate given an UpdateExpr, builds an evalengine.Expr 149 func extractValueFromUpdate(upd *sqlparser.UpdateExpr) (evalengine.Expr, error) { 150 expr := upd.Expr 151 if sq, ok := expr.(*sqlparser.ExtractedSubquery); ok { 152 // if we are planning an update that needs one or more values from the outside, we can trust that they have 153 // been correctly extracted from this query before we reach this far 154 // if NeedsRewrite is true, it means that this subquery was happily merged with the outer. 155 // But in that case we should not be here, so we fail 156 if sq.NeedsRewrite { 157 return nil, invalidUpdateExpr(upd, expr) 158 } 159 expr = sqlparser.NewArgument(sq.GetArgName()) 160 } 161 162 pv, err := evalengine.Translate(expr, semantics.EmptySemTable()) 163 if err != nil || sqlparser.IsSimpleTuple(expr) { 164 return nil, invalidUpdateExpr(upd, expr) 165 } 166 return pv, nil 167 } 168 169 func invalidUpdateExpr(upd *sqlparser.UpdateExpr, expr sqlparser.Expr) error { 170 return vterrors.VT12001(fmt.Sprintf("only values are supported; invalid update on column: `%s` with expr: [%s]", upd.Name.Name.String(), sqlparser.String(expr))) 171 }