vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/delete.go (about) 1 /* 2 Copyright 2019 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 planbuilder 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/plancontext" 24 ) 25 26 // buildDeletePlan builds the instructions for a DELETE statement. 27 func buildDeletePlan(string) stmtPlanner { 28 return func(stmt sqlparser.Statement, reservedVars *sqlparser.ReservedVars, vschema plancontext.VSchema) (*planResult, error) { 29 del := stmt.(*sqlparser.Delete) 30 if del.With != nil { 31 return nil, vterrors.VT12001("WITH expression in DELETE statement") 32 } 33 var err error 34 if len(del.TableExprs) == 1 && len(del.Targets) == 1 { 35 del, err = rewriteSingleTbl(del) 36 if err != nil { 37 return nil, err 38 } 39 } 40 dml, tables, ksidVindex, err := buildDMLPlan(vschema, "delete", del, reservedVars, del.TableExprs, del.Where, del.OrderBy, del.Limit, del.Comments, del.Targets) 41 if err != nil { 42 return nil, err 43 } 44 edel := &engine.Delete{DML: dml} 45 if dml.Opcode == engine.Unsharded { 46 return newPlanResult(edel, tables...), nil 47 } 48 49 if len(del.Targets) > 1 { 50 return nil, vterrors.VT12001("multi-table DELETE statement in a sharded keyspace") 51 } 52 53 edelTable, err := edel.GetSingleTable() 54 if err != nil { 55 return nil, err 56 } 57 if len(del.Targets) == 1 && del.Targets[0].Name != edelTable.Name { 58 return nil, vterrors.VT03003(del.Targets[0].Name.String()) 59 } 60 61 if len(edelTable.Owned) > 0 { 62 aTblExpr, ok := del.TableExprs[0].(*sqlparser.AliasedTableExpr) 63 if !ok { 64 return nil, vterrors.VT12001("deleting from a complex table expression") 65 } 66 tblExpr := &sqlparser.AliasedTableExpr{Expr: sqlparser.TableName{Name: edelTable.Name}, As: aTblExpr.As} 67 edel.OwnedVindexQuery = generateDMLSubquery(tblExpr, del.Where, del.OrderBy, del.Limit, edelTable, ksidVindex.Columns) 68 edel.KsidVindex = ksidVindex.Vindex 69 edel.KsidLength = len(ksidVindex.Columns) 70 } 71 72 return newPlanResult(edel, tables...), nil 73 } 74 } 75 76 func rewriteSingleTbl(del *sqlparser.Delete) (*sqlparser.Delete, error) { 77 atExpr, ok := del.TableExprs[0].(*sqlparser.AliasedTableExpr) 78 if !ok { 79 return del, nil 80 } 81 if !atExpr.As.IsEmpty() && !sqlparser.Equals.IdentifierCS(del.Targets[0].Name, atExpr.As) { 82 // Unknown table in MULTI DELETE 83 return nil, vterrors.VT03003(del.Targets[0].Name.String()) 84 } 85 86 tbl, ok := atExpr.Expr.(sqlparser.TableName) 87 if !ok { 88 // derived table 89 return nil, vterrors.VT03004(atExpr.As.String()) 90 } 91 if atExpr.As.IsEmpty() && !sqlparser.Equals.IdentifierCS(del.Targets[0].Name, tbl.Name) { 92 // Unknown table in MULTI DELETE 93 return nil, vterrors.VT03003(del.Targets[0].Name.String()) 94 } 95 96 del.TableExprs = sqlparser.TableExprs{&sqlparser.AliasedTableExpr{Expr: tbl}} 97 del.Targets = nil 98 if del.Where != nil { 99 _ = sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) { 100 col, ok := node.(*sqlparser.ColName) 101 if !ok { 102 return true, nil 103 } 104 if !col.Qualifier.IsEmpty() { 105 col.Qualifier = tbl 106 } 107 return true, nil 108 }, del.Where) 109 } 110 return del, nil 111 }