vitess.io/vitess@v0.16.2/go/vt/vtgate/engine/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 engine 18 19 import ( 20 "context" 21 "fmt" 22 23 "vitess.io/vitess/go/vt/vtgate/evalengine" 24 25 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 26 27 "vitess.io/vitess/go/sqltypes" 28 "vitess.io/vitess/go/vt/srvtopo" 29 "vitess.io/vitess/go/vt/vtgate/vindexes" 30 31 querypb "vitess.io/vitess/go/vt/proto/query" 32 ) 33 34 var _ Primitive = (*Delete)(nil) 35 36 // Delete represents the instructions to perform a delete. 37 type Delete struct { 38 *DML 39 40 // Delete does not take inputs 41 noInputs 42 } 43 44 // TryExecute performs a non-streaming exec. 45 func (del *Delete) TryExecute(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable, _ bool) (*sqltypes.Result, error) { 46 ctx, cancelFunc := addQueryTimeout(ctx, vcursor, del.QueryTimeout) 47 defer cancelFunc() 48 49 rss, _, err := del.findRoute(ctx, vcursor, bindVars) 50 if err != nil { 51 return nil, err 52 } 53 err = allowOnlyPrimary(rss...) 54 if err != nil { 55 return nil, err 56 } 57 58 switch del.Opcode { 59 case Unsharded: 60 return del.execUnsharded(ctx, del, vcursor, bindVars, rss) 61 case Equal, IN, Scatter, ByDestination, SubShard, EqualUnique, MultiEqual: 62 return del.execMultiDestination(ctx, del, vcursor, bindVars, rss, del.deleteVindexEntries) 63 default: 64 // Unreachable. 65 return nil, fmt.Errorf("unsupported opcode: %v", del.Opcode) 66 } 67 } 68 69 // TryStreamExecute performs a streaming exec. 70 func (del *Delete) TryStreamExecute(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool, callback func(*sqltypes.Result) error) error { 71 res, err := del.TryExecute(ctx, vcursor, bindVars, wantfields) 72 if err != nil { 73 return err 74 } 75 return callback(res) 76 } 77 78 // GetFields fetches the field info. 79 func (del *Delete) GetFields(context.Context, VCursor, map[string]*querypb.BindVariable) (*sqltypes.Result, error) { 80 return nil, fmt.Errorf("BUG: unreachable code for %q", del.Query) 81 } 82 83 // deleteVindexEntries performs an delete if table owns vindex. 84 // Note: the commit order may be different from the DML order because it's possible 85 // for DMLs to reuse existing transactions. 86 func (del *Delete) deleteVindexEntries(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable, rss []*srvtopo.ResolvedShard) error { 87 if del.OwnedVindexQuery == "" { 88 return nil 89 } 90 queries := make([]*querypb.BoundQuery, len(rss)) 91 for i := range rss { 92 queries[i] = &querypb.BoundQuery{Sql: del.OwnedVindexQuery, BindVariables: bindVars} 93 } 94 subQueryResults, errors := vcursor.ExecuteMultiShard(ctx, del, rss, queries, false /* rollbackOnError */, false /* canAutocommit */) 95 for _, err := range errors { 96 if err != nil { 97 return err 98 } 99 } 100 101 if len(subQueryResults.Rows) == 0 { 102 return nil 103 } 104 105 for _, row := range subQueryResults.Rows { 106 ksid, err := resolveKeyspaceID(ctx, vcursor, del.KsidVindex, row[0:del.KsidLength]) 107 if err != nil { 108 return err 109 } 110 colnum := del.KsidLength 111 vindexTable, err := del.GetSingleTable() 112 if err != nil { 113 return err 114 } 115 for _, colVindex := range vindexTable.Owned { 116 // Fetch the column values. colnum must keep incrementing. 117 fromIds := make([]sqltypes.Value, 0, len(colVindex.Columns)) 118 for range colVindex.Columns { 119 fromIds = append(fromIds, row[colnum]) 120 colnum++ 121 } 122 if err := colVindex.Vindex.(vindexes.Lookup).Delete(ctx, vcursor, [][]sqltypes.Value{fromIds}, ksid); err != nil { 123 return err 124 } 125 } 126 } 127 128 return nil 129 } 130 131 func (del *Delete) description() PrimitiveDescription { 132 other := map[string]any{ 133 "Query": del.Query, 134 "Table": del.GetTableName(), 135 "OwnedVindexQuery": del.OwnedVindexQuery, 136 "MultiShardAutocommit": del.MultiShardAutocommit, 137 "QueryTimeout": del.QueryTimeout, 138 } 139 140 addFieldsIfNotEmpty(del.DML, other) 141 142 return PrimitiveDescription{ 143 OperatorType: "Delete", 144 Keyspace: del.Keyspace, 145 Variant: del.Opcode.String(), 146 TargetTabletType: topodatapb.TabletType_PRIMARY, 147 Other: other, 148 } 149 } 150 151 func addFieldsIfNotEmpty(dml *DML, other map[string]any) { 152 if dml.Vindex != nil { 153 other["Vindex"] = dml.Vindex.String() 154 } 155 if dml.KsidVindex != nil { 156 other["KsidVindex"] = dml.KsidVindex.String() 157 other["KsidLength"] = dml.KsidLength 158 } 159 if len(dml.Values) > 0 { 160 s := []string{} 161 for _, value := range dml.Values { 162 s = append(s, evalengine.FormatExpr(value)) 163 } 164 other["Values"] = s 165 } 166 }