github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/row/deleter.go (about) 1 // Copyright 2019 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package row 12 13 import ( 14 "context" 15 16 "github.com/cockroachdb/cockroach/pkg/keys" 17 "github.com/cockroachdb/cockroach/pkg/kv" 18 "github.com/cockroachdb/cockroach/pkg/roachpb" 19 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 20 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 21 "github.com/cockroachdb/cockroach/pkg/util/log" 22 ) 23 24 // Deleter abstracts the key/value operations for deleting table rows. 25 type Deleter struct { 26 Helper rowHelper 27 FetchCols []sqlbase.ColumnDescriptor 28 FetchColIDtoRowIndex map[sqlbase.ColumnID]int 29 Fks fkExistenceCheckForDelete 30 cascader *cascader 31 // For allocation avoidance. 32 key roachpb.Key 33 } 34 35 // MakeDeleter creates a Deleter for the given table. 36 // 37 // The returned Deleter contains a FetchCols field that defines the 38 // expectation of which values are passed as values to DeleteRow. Any column 39 // passed in requestedCols will be included in FetchCols. 40 func MakeDeleter( 41 ctx context.Context, 42 txn *kv.Txn, 43 codec keys.SQLCodec, 44 tableDesc *sqlbase.ImmutableTableDescriptor, 45 fkTables FkTableMetadata, 46 requestedCols []sqlbase.ColumnDescriptor, 47 checkFKs checkFKConstraints, 48 evalCtx *tree.EvalContext, 49 alloc *sqlbase.DatumAlloc, 50 ) (Deleter, error) { 51 rowDeleter, err := makeRowDeleterWithoutCascader( 52 ctx, txn, codec, tableDesc, fkTables, requestedCols, checkFKs, alloc, 53 ) 54 if err != nil { 55 return Deleter{}, err 56 } 57 if checkFKs == CheckFKs { 58 var err error 59 rowDeleter.cascader, err = makeDeleteCascader(ctx, txn, tableDesc, fkTables, evalCtx, alloc) 60 if err != nil { 61 return Deleter{}, err 62 } 63 // If we are performing a cascade operation for a particular foreign 64 // key constraint, we don't also need to perform a foreign key 65 // existence check after the delete for the same foreign key 66 // constraint. This pass removes unnecessary existence helpers. 67 // In particular, we omit checks for CASCADE and SET NULL because 68 // after the cascader has finished deleting or setting rows to 69 // NULL, we don't need to verify the result of those operations. 70 // TODO (rohany): This code will be removed once the optimizer 71 // handles cascade operations. 72 for k, helpers := range rowDeleter.Fks.fks { 73 index := 0 74 for i := range helpers { 75 helper := &helpers[i] 76 if helper.ref.OnDelete == sqlbase.ForeignKeyReference_CASCADE || 77 helper.ref.OnDelete == sqlbase.ForeignKeyReference_SET_NULL { 78 continue 79 } 80 helpers[index] = *helper 81 index++ 82 } 83 rowDeleter.Fks.fks[k] = helpers[:index] 84 } 85 } 86 return rowDeleter, nil 87 } 88 89 // makeRowDeleterWithoutCascader creates a rowDeleter but does not create an 90 // additional cascader. 91 func makeRowDeleterWithoutCascader( 92 ctx context.Context, 93 txn *kv.Txn, 94 codec keys.SQLCodec, 95 tableDesc *sqlbase.ImmutableTableDescriptor, 96 fkTables FkTableMetadata, 97 requestedCols []sqlbase.ColumnDescriptor, 98 checkFKs checkFKConstraints, 99 alloc *sqlbase.DatumAlloc, 100 ) (Deleter, error) { 101 indexes := tableDesc.DeletableIndexes() 102 103 fetchCols := requestedCols[:len(requestedCols):len(requestedCols)] 104 fetchColIDtoRowIndex := ColIDtoRowIndexFromCols(fetchCols) 105 106 maybeAddCol := func(colID sqlbase.ColumnID) error { 107 if _, ok := fetchColIDtoRowIndex[colID]; !ok { 108 col, err := tableDesc.FindColumnByID(colID) 109 if err != nil { 110 return err 111 } 112 fetchColIDtoRowIndex[col.ID] = len(fetchCols) 113 fetchCols = append(fetchCols, *col) 114 } 115 return nil 116 } 117 for _, colID := range tableDesc.PrimaryIndex.ColumnIDs { 118 if err := maybeAddCol(colID); err != nil { 119 return Deleter{}, err 120 } 121 } 122 for _, index := range indexes { 123 for _, colID := range index.ColumnIDs { 124 if err := maybeAddCol(colID); err != nil { 125 return Deleter{}, err 126 } 127 } 128 // The extra columns are needed to fix #14601. 129 for _, colID := range index.ExtraColumnIDs { 130 if err := maybeAddCol(colID); err != nil { 131 return Deleter{}, err 132 } 133 } 134 } 135 136 rd := Deleter{ 137 Helper: newRowHelper(codec, tableDesc, indexes), 138 FetchCols: fetchCols, 139 FetchColIDtoRowIndex: fetchColIDtoRowIndex, 140 } 141 if checkFKs == CheckFKs { 142 var err error 143 if rd.Fks, err = makeFkExistenceCheckHelperForDelete(ctx, txn, codec, tableDesc, fkTables, 144 fetchColIDtoRowIndex, alloc); err != nil { 145 return Deleter{}, err 146 } 147 } 148 149 return rd, nil 150 } 151 152 // DeleteRow adds to the batch the kv operations necessary to delete a table row 153 // with the given values. It also will cascade as required and check for 154 // orphaned rows. The bytesMonitor is only used if cascading/fk checking and can 155 // be nil if not. 156 func (rd *Deleter) DeleteRow( 157 ctx context.Context, b *kv.Batch, values []tree.Datum, checkFKs checkFKConstraints, traceKV bool, 158 ) error { 159 160 // Delete the row from any secondary indices. 161 for i := range rd.Helper.Indexes { 162 // We want to include empty k/v pairs because we want to delete all k/v's for this row. 163 entries, err := sqlbase.EncodeSecondaryIndex( 164 rd.Helper.Codec, 165 rd.Helper.TableDesc.TableDesc(), 166 &rd.Helper.Indexes[i], 167 rd.FetchColIDtoRowIndex, 168 values, 169 true, /* includeEmpty */ 170 ) 171 if err != nil { 172 return err 173 } 174 for _, e := range entries { 175 if traceKV { 176 log.VEventf(ctx, 2, "Del %s", keys.PrettyPrint(rd.Helper.secIndexValDirs[i], e.Key)) 177 } 178 b.Del(&e.Key) 179 } 180 } 181 182 primaryIndexKey, err := rd.Helper.encodePrimaryIndex(rd.FetchColIDtoRowIndex, values) 183 if err != nil { 184 return err 185 } 186 187 // Delete the row. 188 for i := range rd.Helper.TableDesc.Families { 189 if i > 0 { 190 // HACK: MakeFamilyKey appends to its argument, so on every loop iteration 191 // after the first, trim primaryIndexKey so nothing gets overwritten. 192 // TODO(dan): Instead of this, use something like engine.ChunkAllocator. 193 primaryIndexKey = primaryIndexKey[:len(primaryIndexKey):len(primaryIndexKey)] 194 } 195 familyID := rd.Helper.TableDesc.Families[i].ID 196 rd.key = keys.MakeFamilyKey(primaryIndexKey, uint32(familyID)) 197 if traceKV { 198 log.VEventf(ctx, 2, "Del %s", keys.PrettyPrint(rd.Helper.primIndexValDirs, rd.key)) 199 } 200 b.Del(&rd.key) 201 rd.key = nil 202 } 203 204 if rd.cascader != nil { 205 if err := rd.cascader.cascadeAll( 206 ctx, 207 rd.Helper.TableDesc, 208 tree.Datums(values), 209 nil, /* updatedValues */ 210 rd.FetchColIDtoRowIndex, 211 traceKV, 212 ); err != nil { 213 return err 214 } 215 } 216 if rd.Fks.checker != nil && checkFKs == CheckFKs { 217 if err := rd.Fks.addAllIdxChecks(ctx, values, traceKV); err != nil { 218 return err 219 } 220 return rd.Fks.checker.runCheck(ctx, values, nil) 221 } 222 return nil 223 } 224 225 // DeleteIndexRow adds to the batch the kv operations necessary to delete a 226 // table row from the given index. 227 func (rd *Deleter) DeleteIndexRow( 228 ctx context.Context, b *kv.Batch, idx *sqlbase.IndexDescriptor, values []tree.Datum, traceKV bool, 229 ) error { 230 if rd.Fks.checker != nil { 231 if err := rd.Fks.addAllIdxChecks(ctx, values, traceKV); err != nil { 232 return err 233 } 234 if err := rd.Fks.checker.runCheck(ctx, values, nil); err != nil { 235 return err 236 } 237 } 238 // We want to include empty k/v pairs because we want 239 // to delete all k/v's for this row. By setting includeEmpty 240 // to true, we will get a k/v pair for each family in the row, 241 // which will guarantee that we delete all the k/v's in this row. 242 secondaryIndexEntry, err := sqlbase.EncodeSecondaryIndex( 243 rd.Helper.Codec, 244 rd.Helper.TableDesc.TableDesc(), 245 idx, 246 rd.FetchColIDtoRowIndex, 247 values, 248 true, /* includeEmpty */ 249 ) 250 if err != nil { 251 return err 252 } 253 254 for _, entry := range secondaryIndexEntry { 255 if traceKV { 256 log.VEventf(ctx, 2, "Del %s", entry.Key) 257 } 258 b.Del(entry.Key) 259 } 260 return nil 261 }