github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/delete.go (about)

     1  // Copyright 2015 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 sql
    12  
    13  import (
    14  	"context"
    15  	"sync"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/sql/rowcontainer"
    18  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    20  	"github.com/cockroachdb/cockroach/pkg/util"
    21  	"github.com/cockroachdb/cockroach/pkg/util/tracing"
    22  )
    23  
    24  var deleteNodePool = sync.Pool{
    25  	New: func() interface{} {
    26  		return &deleteNode{}
    27  	},
    28  }
    29  
    30  type deleteNode struct {
    31  	source planNode
    32  
    33  	// columns is set if this DELETE is returning any rows, to be
    34  	// consumed by a renderNode upstream. This occurs when there is a
    35  	// RETURNING clause with some scalar expressions.
    36  	columns sqlbase.ResultColumns
    37  
    38  	run deleteRun
    39  }
    40  
    41  // deleteRun contains the run-time state of deleteNode during local execution.
    42  type deleteRun struct {
    43  	td         tableDeleter
    44  	rowsNeeded bool
    45  
    46  	// rowCount is the number of rows in the current batch.
    47  	rowCount int
    48  
    49  	// done informs a new call to BatchedNext() that the previous call
    50  	// to BatchedNext() has completed the work already.
    51  	done bool
    52  
    53  	// rows contains the accumulated result rows if rowsNeeded is set.
    54  	rows *rowcontainer.RowContainer
    55  
    56  	// traceKV caches the current KV tracing flag.
    57  	traceKV bool
    58  
    59  	// rowIdxToRetIdx is the mapping from the columns returned by the deleter
    60  	// to the columns in the resultRowBuffer. A value of -1 is used to indicate
    61  	// that the column at that index is not part of the resultRowBuffer
    62  	// of the mutation. Otherwise, the value at the i-th index refers to the
    63  	// index of the resultRowBuffer where the i-th column is to be returned.
    64  	rowIdxToRetIdx []int
    65  }
    66  
    67  // maxDeleteBatchSize is the max number of entries in the KV batch for
    68  // the delete operation (including secondary index updates, FK
    69  // cascading updates, etc), before the current KV batch is executed
    70  // and a new batch is started.
    71  const maxDeleteBatchSize = 10000
    72  
    73  func (d *deleteNode) startExec(params runParams) error {
    74  	// cache traceKV during execution, to avoid re-evaluating it for every row.
    75  	d.run.traceKV = params.p.ExtendedEvalContext().Tracing.KVTracingEnabled()
    76  
    77  	if d.run.rowsNeeded {
    78  		d.run.rows = rowcontainer.NewRowContainer(
    79  			params.EvalContext().Mon.MakeBoundAccount(),
    80  			sqlbase.ColTypeInfoFromResCols(d.columns), 0)
    81  	}
    82  	return d.run.td.init(params.ctx, params.p.txn, params.EvalContext())
    83  }
    84  
    85  // Next is required because batchedPlanNode inherits from planNode, but
    86  // batchedPlanNode doesn't really provide it. See the explanatory comments
    87  // in plan_batch.go.
    88  func (d *deleteNode) Next(params runParams) (bool, error) { panic("not valid") }
    89  
    90  // Values is required because batchedPlanNode inherits from planNode, but
    91  // batchedPlanNode doesn't really provide it. See the explanatory comments
    92  // in plan_batch.go.
    93  func (d *deleteNode) Values() tree.Datums { panic("not valid") }
    94  
    95  // BatchedNext implements the batchedPlanNode interface.
    96  func (d *deleteNode) BatchedNext(params runParams) (bool, error) {
    97  	if d.run.done {
    98  		return false, nil
    99  	}
   100  
   101  	tracing.AnnotateTrace()
   102  
   103  	// Advance one batch. First, clear the current batch.
   104  	d.run.rowCount = 0
   105  	if d.run.rows != nil {
   106  		d.run.rows.Clear(params.ctx)
   107  	}
   108  	// Now consume/accumulate the rows for this batch.
   109  	lastBatch := false
   110  	for {
   111  		if err := params.p.cancelChecker.Check(); err != nil {
   112  			return false, err
   113  		}
   114  
   115  		// Advance one individual row.
   116  		if next, err := d.source.Next(params); !next {
   117  			lastBatch = true
   118  			if err != nil {
   119  				return false, err
   120  			}
   121  			break
   122  		}
   123  
   124  		// Process the deletion of the current source row,
   125  		// potentially accumulating the result row for later.
   126  		if err := d.processSourceRow(params, d.source.Values()); err != nil {
   127  			return false, err
   128  		}
   129  
   130  		d.run.rowCount++
   131  
   132  		// Are we done yet with the current batch?
   133  		if d.run.td.curBatchSize() >= maxDeleteBatchSize {
   134  			break
   135  		}
   136  	}
   137  
   138  	if d.run.rowCount > 0 {
   139  		if err := d.run.td.atBatchEnd(params.ctx, d.run.traceKV); err != nil {
   140  			return false, err
   141  		}
   142  
   143  		if !lastBatch {
   144  			// We only run/commit the batch if there were some rows processed
   145  			// in this batch.
   146  			if err := d.run.td.flushAndStartNewBatch(params.ctx); err != nil {
   147  				return false, err
   148  			}
   149  		}
   150  	}
   151  
   152  	if lastBatch {
   153  		if _, err := d.run.td.finalize(params.ctx, d.run.traceKV); err != nil {
   154  			return false, err
   155  		}
   156  		// Remember we're done for the next call to BatchedNext().
   157  		d.run.done = true
   158  	}
   159  
   160  	// Possibly initiate a run of CREATE STATISTICS.
   161  	params.ExecCfg().StatsRefresher.NotifyMutation(
   162  		d.run.td.tableDesc().ID,
   163  		d.run.rowCount,
   164  	)
   165  
   166  	return d.run.rowCount > 0, nil
   167  }
   168  
   169  // processSourceRow processes one row from the source for deletion and, if
   170  // result rows are needed, saves it in the result row container
   171  func (d *deleteNode) processSourceRow(params runParams, sourceVals tree.Datums) error {
   172  	// Queue the deletion in the KV batch.
   173  	// TODO(mgartner): Add partial index IDs to ignoreIndexes that we should
   174  	// not delete entries from.
   175  	var ignoreIndexes util.FastIntSet
   176  	if err := d.run.td.row(params.ctx, sourceVals, ignoreIndexes, d.run.traceKV); err != nil {
   177  		return err
   178  	}
   179  
   180  	// If result rows need to be accumulated, do it.
   181  	if d.run.rows != nil {
   182  		// The new values can include all columns, the construction of the
   183  		// values has used execinfra.ScanVisibilityPublicAndNotPublic so the
   184  		// values may contain additional columns for every newly dropped column
   185  		// not visible. We do not want them to be available for RETURNING.
   186  		//
   187  		// d.run.rows.NumCols() is guaranteed to only contain the requested
   188  		// public columns.
   189  		resultValues := make(tree.Datums, d.run.rows.NumCols())
   190  		for i, retIdx := range d.run.rowIdxToRetIdx {
   191  			if retIdx >= 0 {
   192  				resultValues[retIdx] = sourceVals[i]
   193  			}
   194  		}
   195  
   196  		if _, err := d.run.rows.AddRow(params.ctx, resultValues); err != nil {
   197  			return err
   198  		}
   199  	}
   200  
   201  	return nil
   202  }
   203  
   204  // BatchedCount implements the batchedPlanNode interface.
   205  func (d *deleteNode) BatchedCount() int { return d.run.rowCount }
   206  
   207  // BatchedCount implements the batchedPlanNode interface.
   208  func (d *deleteNode) BatchedValues(rowIdx int) tree.Datums { return d.run.rows.At(rowIdx) }
   209  
   210  func (d *deleteNode) Close(ctx context.Context) {
   211  	d.source.Close(ctx)
   212  	if d.run.rows != nil {
   213  		d.run.rows.Close(ctx)
   214  		d.run.rows = nil
   215  	}
   216  	d.run.td.close(ctx)
   217  	*d = deleteNode{}
   218  	deleteNodePool.Put(d)
   219  }
   220  
   221  func (d *deleteNode) enableAutoCommit() {
   222  	d.run.td.enableAutoCommit()
   223  }