func (td *tableDeleter) deleteAllRowsScan(ctx context.Context) error { tablePrefix := sqlbase.MakeIndexKeyPrefix( td.rd.helper.tableDesc, td.rd.helper.tableDesc.PrimaryIndex.ID) span := sqlbase.Span{Start: roachpb.Key(tablePrefix), End: roachpb.Key(tablePrefix).PrefixEnd()} valNeededForCol := make([]bool, len(td.rd.helper.tableDesc.Columns)) for _, idx := range td.rd.fetchColIDtoRowIndex { valNeededForCol[idx] = true } var rf sqlbase.RowFetcher err := rf.Init( td.rd.helper.tableDesc, td.rd.fetchColIDtoRowIndex, &td.rd.helper.tableDesc.PrimaryIndex, false, false, td.rd.fetchCols, valNeededForCol) if err != nil { return err } if err := rf.StartScan(td.txn, sqlbase.Spans{span}, 0); err != nil { return err } for { row, err := rf.NextRow() if err != nil { return err } if row == nil { // Done deleting rows. break } _, err = td.row(ctx, row) if err != nil { return err } } return td.finalize(ctx) }
func (sc *SchemaChanger) truncateAndBackfillColumnsChunk( added []sqlbase.ColumnDescriptor, dropped []sqlbase.ColumnDescriptor, defaultExprs []parser.TypedExpr, evalCtx *parser.EvalContext, sp sqlbase.Span, ) (roachpb.Key, bool, error) { var curIndexKey roachpb.Key done := false err := sc.db.Txn(func(txn *client.Txn) error { tableDesc, err := getTableDescFromID(txn, sc.tableID) if err != nil { return err } // Short circuit the backfill if the table has been deleted. if tableDesc.Deleted() { done = true return nil } updateCols := append(added, dropped...) fkTables := TablesNeededForFKs(*tableDesc, CheckUpdates) for k := range fkTables { if fkTables[k], err = getTableDescFromID(txn, k); err != nil { return err } } // TODO(dan): Tighten up the bound on the requestedCols parameter to // makeRowUpdater. requestedCols := make([]sqlbase.ColumnDescriptor, 0, len(tableDesc.Columns)+len(added)) requestedCols = append(requestedCols, tableDesc.Columns...) requestedCols = append(requestedCols, added...) ru, err := makeRowUpdater( txn, tableDesc, fkTables, updateCols, requestedCols, rowUpdaterOnlyColumns, ) if err != nil { return err } // TODO(dan): This check is an unfortunate bleeding of the internals of // rowUpdater. Extract the sql row to k/v mapping logic out into something // usable here. if !ru.isColumnOnlyUpdate() { panic("only column data should be modified, but the rowUpdater is configured otherwise") } // Run a scan across the table using the primary key. Running // the scan and applying the changes in many transactions is // fine because the schema change is in the correct state to // handle intermediate OLTP commands which delete and add // values during the scan. var rf sqlbase.RowFetcher colIDtoRowIndex := colIDtoRowIndexFromCols(tableDesc.Columns) valNeededForCol := make([]bool, len(tableDesc.Columns)) for i := range valNeededForCol { _, valNeededForCol[i] = ru.fetchColIDtoRowIndex[tableDesc.Columns[i].ID] } err = rf.Init(tableDesc, colIDtoRowIndex, &tableDesc.PrimaryIndex, false, false, tableDesc.Columns, valNeededForCol) if err != nil { return err } // StartScan uses 0 as a sentinal for the default limit of entries scanned. if err := rf.StartScan(txn, sqlbase.Spans{sp}, 0); err != nil { return err } indexKeyPrefix := sqlbase.MakeIndexKeyPrefix(tableDesc, tableDesc.PrimaryIndex.ID) oldValues := make(parser.DTuple, len(ru.fetchCols)) updateValues := make(parser.DTuple, len(updateCols)) writeBatch := &client.Batch{} var i int for ; i < ColumnTruncateAndBackfillChunkSize; i++ { row, err := rf.NextRow() if err != nil { return err } if row == nil { break // Done } curIndexKey, _, err = sqlbase.EncodeIndexKey( tableDesc, &tableDesc.PrimaryIndex, colIDtoRowIndex, row, indexKeyPrefix) for j, col := range added { if defaultExprs == nil || defaultExprs[j] == nil { updateValues[j] = parser.DNull } else { updateValues[j], err = defaultExprs[j].Eval(evalCtx) if err != nil { return err } } if !col.Nullable && updateValues[j].Compare(parser.DNull) == 0 { return sqlbase.NewNonNullViolationError(col.Name) } } for j := range dropped { updateValues[j+len(added)] = parser.DNull } copy(oldValues, row) for j := len(row); j < len(oldValues); j++ { oldValues[j] = parser.DNull } if _, err := ru.updateRow(writeBatch, oldValues, updateValues); err != nil { return err } } if i < ColumnTruncateAndBackfillChunkSize { done = true } if err := txn.Run(writeBatch); err != nil { return convertBackfillError(tableDesc, writeBatch) } return nil }) return curIndexKey.PrefixEnd(), done, err }