func setRow(txn kv.Transaction, handle int64, tbl *simpleTableInfo, gen genValueFunc) error { rowKey := tablecodec.EncodeRowKey(tbl.tID, codec.EncodeInt(nil, handle)) columnValues := gen(handle, tbl) value, err := tablecodec.EncodeRow(columnValues, tbl.cIDs) if err != nil { return errors.Trace(err) } err = txn.Set(rowKey, value) if err != nil { return errors.Trace(err) } for i, idxCol := range tbl.indices { idxVal := columnValues[idxCol] encoded, err := codec.EncodeKey(nil, idxVal, types.NewDatum(handle)) if err != nil { return errors.Trace(err) } idxKey := tablecodec.EncodeIndexSeekKey(tbl.tID, tbl.iIDs[i], encoded) err = txn.Set(idxKey, []byte{0}) if err != nil { return errors.Trace(err) } } return nil }
func (t *Table) addUpdateBinlog(ctx context.Context, h int64, old []types.Datum, newValue []byte, colIDs []int64) error { mutation := t.getMutation(ctx) hasPK := false if t.meta.PKIsHandle { hasPK = true } else { for _, idx := range t.meta.Indices { if idx.Primary { hasPK = true break } } } var bin []byte if hasPK { handleData, _ := codec.EncodeValue(nil, types.NewIntDatum(h)) bin = append(handleData, newValue...) } else { oldData, err := tablecodec.EncodeRow(old, colIDs) if err != nil { return errors.Trace(err) } bin = append(oldData, newValue...) } mutation.UpdatedRows = append(mutation.UpdatedRows, bin) mutation.Sequence = append(mutation.Sequence, binlog.MutationType_Update) return nil }
func setColValue(c *C, txn kv.Transaction, key kv.Key, v types.Datum) { row := []types.Datum{v, {}} colIDs := []int64{2, 3} value, err := tablecodec.EncodeRow(row, colIDs) c.Assert(err, IsNil) err = txn.Set(key, value) c.Assert(err, IsNil) }
func (d *ddl) backfillColumnData(t table.Table, columnInfo *model.ColumnInfo, handles []int64, reorgInfo *reorgInfo) error { defaultVal, _, err := table.GetColDefaultValue(nil, columnInfo) if err != nil { return errors.Trace(err) } colMap := make(map[int64]*types.FieldType) for _, col := range t.Meta().Columns { colMap[col.ID] = &col.FieldType } for _, handle := range handles { log.Info("[ddl] backfill column...", handle) err := kv.RunInNewTxn(d.store, true, func(txn kv.Transaction) error { if err := d.isReorgRunnable(txn); err != nil { return errors.Trace(err) } rowKey := t.RecordKey(handle) rowVal, err := txn.Get(rowKey) if terror.ErrorEqual(err, kv.ErrNotExist) { // If row doesn't exist, skip it. return nil } if err != nil { return errors.Trace(err) } rowColumns, err := tablecodec.DecodeRow(rowVal, colMap) if err != nil { return errors.Trace(err) } if _, ok := rowColumns[columnInfo.ID]; ok { // The column is already added by update or insert statement, skip it. return nil } newColumnIDs := make([]int64, 0, len(rowColumns)+1) newRow := make([]types.Datum, 0, len(rowColumns)+1) for colID, val := range rowColumns { newColumnIDs = append(newColumnIDs, colID) newRow = append(newRow, val) } newColumnIDs = append(newColumnIDs, columnInfo.ID) newRow = append(newRow, defaultVal) newRowVal, err := tablecodec.EncodeRow(newRow, newColumnIDs) if err != nil { return errors.Trace(err) } err = txn.Set(rowKey, newRowVal) if err != nil { return errors.Trace(err) } return errors.Trace(reorgInfo.UpdateHandle(txn, handle)) }) if err != nil { return errors.Trace(err) } } return nil }
// UpdateRecord implements table.Table UpdateRecord interface. func (t *Table) UpdateRecord(ctx context.Context, h int64, oldData []types.Datum, newData []types.Datum, touched map[int]bool) error { // We should check whether this table has on update column which state is write only. currentData := make([]types.Datum, len(t.WritableCols())) copy(currentData, newData) // If they are not set, and other data are changed, they will be updated by current timestamp too. err := t.setOnUpdateData(ctx, touched, currentData) if err != nil { return errors.Trace(err) } txn, err := ctx.GetTxn(false) if err != nil { return errors.Trace(err) } bs := kv.NewBufferStore(txn) // Compose new row t.composeNewData(touched, currentData, oldData) colIDs := make([]int64, 0, len(t.WritableCols())) for i, col := range t.WritableCols() { if col.State != model.StatePublic && currentData[i].IsNull() { defaultVal, _, err1 := table.GetColDefaultValue(ctx, col.ToInfo()) if err1 != nil { return errors.Trace(err1) } currentData[i] = defaultVal } colIDs = append(colIDs, col.ID) } // Set new row data into KV. key := t.RecordKey(h) value, err := tablecodec.EncodeRow(currentData, colIDs) if err = txn.Set(key, value); err != nil { return errors.Trace(err) } if err = bs.SaveTo(txn); err != nil { return errors.Trace(err) } // rebuild index if err = t.rebuildIndices(bs, h, touched, oldData, currentData); err != nil { return errors.Trace(err) } err = bs.SaveTo(txn) if err != nil { return errors.Trace(err) } if shouldWriteBinlog(ctx) { t.addUpdateBinlog(ctx, h, oldData, value, colIDs) } return nil }
// UpdateRecord implements table.Table UpdateRecord interface. func (t *Table) UpdateRecord(ctx context.Context, h int64, oldData []types.Datum, newData []types.Datum, touched map[int]bool) error { // We should check whether this table has on update column which state is write only. currentData := make([]types.Datum, len(t.writableCols())) copy(currentData, newData) // If they are not set, and other data are changed, they will be updated by current timestamp too. err := t.setOnUpdateData(ctx, touched, currentData) if err != nil { return errors.Trace(err) } txn, err := ctx.GetTxn(false) if err != nil { return errors.Trace(err) } bs := kv.NewBufferStore(txn) defer bs.Release() // Compose new row t.composeNewData(touched, currentData, oldData) colIDs := make([]int64, 0, len(t.writableCols())) for _, col := range t.writableCols() { colIDs = append(colIDs, col.ID) } // Set new row data into KV. key := t.RecordKey(h) value, err := tablecodec.EncodeRow(currentData, colIDs) if err = txn.Set(key, value); err != nil { return errors.Trace(err) } if err = bs.SaveTo(txn); err != nil { return errors.Trace(err) } // rebuild index if err = t.rebuildIndices(bs, h, touched, oldData, currentData); err != nil { return errors.Trace(err) } err = bs.SaveTo(txn) if err != nil { return errors.Trace(err) } return nil }
// backfillColumnInTxn deals with a part of backfilling column data in a Transaction. // This part of the column data rows is defaultSmallBatchCnt. func (d *ddl) backfillColumnInTxn(t table.Table, colID int64, handles []int64, colMap map[int64]*types.FieldType, defaultVal types.Datum, txn kv.Transaction) (int64, error) { nextHandle := handles[0] for _, handle := range handles { log.Debug("[ddl] backfill column...", handle) rowKey := t.RecordKey(handle) rowVal, err := txn.Get(rowKey) if terror.ErrorEqual(err, kv.ErrNotExist) { // If row doesn't exist, skip it. continue } if err != nil { return 0, errors.Trace(err) } rowColumns, err := tablecodec.DecodeRow(rowVal, colMap) if err != nil { return 0, errors.Trace(err) } if _, ok := rowColumns[colID]; ok { // The column is already added by update or insert statement, skip it. continue } newColumnIDs := make([]int64, 0, len(rowColumns)+1) newRow := make([]types.Datum, 0, len(rowColumns)+1) for colID, val := range rowColumns { newColumnIDs = append(newColumnIDs, colID) newRow = append(newRow, val) } newColumnIDs = append(newColumnIDs, colID) newRow = append(newRow, defaultVal) newRowVal, err := tablecodec.EncodeRow(newRow, newColumnIDs) if err != nil { return 0, errors.Trace(err) } err = txn.Set(rowKey, newRowVal) if err != nil { return 0, errors.Trace(err) } } return nextHandle, nil }
func (t *Table) addDeleteBinlog(ctx context.Context, h int64, r []types.Datum) error { mutation := t.getMutation(ctx) if t.meta.PKIsHandle { mutation.DeletedIds = append(mutation.DeletedIds, h) mutation.Sequence = append(mutation.Sequence, binlog.MutationType_DeleteID) return nil } var primaryIdx *model.IndexInfo for _, idx := range t.meta.Indices { if idx.Primary { primaryIdx = idx break } } var data []byte var err error if primaryIdx != nil { indexedValues := make([]types.Datum, len(primaryIdx.Columns)) for i := range indexedValues { indexedValues[i] = r[primaryIdx.Columns[i].Offset] } data, err = codec.EncodeKey(nil, indexedValues...) if err != nil { return errors.Trace(err) } mutation.DeletedPks = append(mutation.DeletedPks, data) mutation.Sequence = append(mutation.Sequence, binlog.MutationType_DeletePK) return nil } colIDs := make([]int64, len(t.Cols())) for i, col := range t.Cols() { colIDs[i] = col.ID } data, err = tablecodec.EncodeRow(r, colIDs) if err != nil { return errors.Trace(err) } mutation.DeletedRows = append(mutation.DeletedRows, data) mutation.Sequence = append(mutation.Sequence, binlog.MutationType_DeleteRow) return nil }
// AddRecord implements table.Table AddRecord interface. func (t *Table) AddRecord(ctx context.Context, r []types.Datum) (recordID int64, err error) { var hasRecordID bool for _, col := range t.Cols() { if col.IsPKHandleColumn(t.meta) { recordID = r[col.Offset].GetInt64() hasRecordID = true break } } if !hasRecordID { recordID, err = t.alloc.Alloc(t.ID) if err != nil { return 0, errors.Trace(err) } } txn, err := ctx.GetTxn(false) if err != nil { return 0, errors.Trace(err) } bs := kv.NewBufferStore(txn) // Insert new entries into indices. h, err := t.addIndices(ctx, recordID, r, bs) if err != nil { return h, errors.Trace(err) } colIDs := make([]int64, 0, len(r)) row := make([]types.Datum, 0, len(r)) // Set public and write only column value. for _, col := range t.WritableCols() { if col.IsPKHandleColumn(t.meta) { continue } var value types.Datum if col.State == model.StateWriteOnly || col.State == model.StateWriteReorganization { // if col is in write only or write reorganization state, we must add it with its default value. value, _, err = table.GetColDefaultValue(ctx, col.ToInfo()) if err != nil { return 0, errors.Trace(err) } } else { value = r[col.Offset] if col.DefaultValue == nil && r[col.Offset].IsNull() { // Save storage space by not storing null value. continue } } colIDs = append(colIDs, col.ID) row = append(row, value) } key := t.RecordKey(recordID) value, err := tablecodec.EncodeRow(row, colIDs) if err != nil { return 0, errors.Trace(err) } if err = txn.Set(key, value); err != nil { return 0, errors.Trace(err) } if err = bs.SaveTo(txn); err != nil { return 0, errors.Trace(err) } if shouldWriteBinlog(ctx) { mutation := t.getMutation(ctx) // prepend handle to the row value handleVal, _ := codec.EncodeValue(nil, types.NewIntDatum(recordID)) bin := append(handleVal, value...) mutation.InsertedRows = append(mutation.InsertedRows, bin) mutation.Sequence = append(mutation.Sequence, binlog.MutationType_Insert) } ctx.GetSessionVars().StmtCtx.AddAffectedRows(1) return recordID, nil }
// AddRecord implements table.Table AddRecord interface. func (t *Table) AddRecord(ctx context.Context, r []types.Datum) (recordID int64, err error) { var hasRecordID bool for _, col := range t.Cols() { if col.IsPKHandleColumn(t.meta) { recordID = r[col.Offset].GetInt64() hasRecordID = true break } } if !hasRecordID { recordID, err = t.alloc.Alloc(t.ID) if err != nil { return 0, errors.Trace(err) } } txn, err := ctx.GetTxn(false) if err != nil { return 0, errors.Trace(err) } bs := kv.NewBufferStore(txn) defer bs.Release() // Insert new entries into indices. h, err := t.addIndices(ctx, recordID, r, bs) if err != nil { return h, errors.Trace(err) } colIDs := make([]int64, 0, len(r)) row := make([]types.Datum, 0, len(r)) // Set public and write only column value. for _, col := range t.writableCols() { if col.IsPKHandleColumn(t.meta) { continue } if col.DefaultValue == nil && r[col.Offset].IsNull() { // Save storage space by not storing null value. continue } var value types.Datum if col.State == model.StateWriteOnly || col.State == model.StateWriteReorganization { // if col is in write only or write reorganization state, we must add it with its default value. value, _, err = table.GetColDefaultValue(ctx, &col.ColumnInfo) if err != nil { return 0, errors.Trace(err) } } else { value = r[col.Offset] } colIDs = append(colIDs, col.ID) row = append(row, value) } key := t.RecordKey(recordID) value, err := tablecodec.EncodeRow(row, colIDs) if err != nil { return 0, errors.Trace(err) } if err = txn.Set(key, value); err != nil { return 0, errors.Trace(err) } if err = bs.SaveTo(txn); err != nil { return 0, errors.Trace(err) } variable.GetSessionVars(ctx).AddAffectedRows(1) return recordID, nil }