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  }