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 }