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  }