예제 #1
0
파일: xapi_test.go 프로젝트: pingcap/tidb
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
}
예제 #2
0
파일: tables.go 프로젝트: pingcap/tidb
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
}
예제 #3
0
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)
}
예제 #4
0
파일: column.go 프로젝트: duzhanyuan/tidb
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
}
예제 #5
0
파일: tables.go 프로젝트: pingcap/tidb
// 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
}
예제 #6
0
파일: tables.go 프로젝트: xxwwbb3/tidb
// 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
}
예제 #7
0
파일: column.go 프로젝트: pingcap/tidb
// 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
}
예제 #8
0
파일: tables.go 프로젝트: pingcap/tidb
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
}
예제 #9
0
파일: tables.go 프로젝트: pingcap/tidb
// 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
}
예제 #10
0
파일: tables.go 프로젝트: twkun/tidb
// 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
}