Esempio n. 1
0
func (d *ddl) deleteTableData(ctx context.Context, t table.Table) error {
	// Remove data
	err := t.Truncate(ctx)
	if err != nil {
		return errors.Trace(err)
	}
	txn, err := ctx.GetTxn(false)
	if err != nil {
		return errors.Trace(err)
	}
	// Remove indices
	for _, v := range t.Indices() {
		if v != nil && v.X != nil {
			if err = v.X.Drop(txn); err != nil {
				return errors.Trace(err)
			}
		}
	}
	// Remove auto ID key
	err = txn.Delete([]byte(meta.AutoIDKey(t.TableID())))

	// Auto ID meta is created when the first time used, so it may not exist.
	if errors2.ErrorEqual(err, kv.ErrNotExist) {
		return nil
	}
	return errors.Trace(err)
}
Esempio n. 2
0
// Add a column into table
func (d *ddl) addColumn(ctx context.Context, schema model.CIStr, tbl table.Table, spec *AlterSpecification) error {
	// Find position
	cols := tbl.Cols()
	position := len(cols)
	name := spec.Column.Name
	// Check column name duplicate
	dc := column.FindCol(cols, name)
	if dc != nil {
		return errors.Errorf("Try to add a column with the same name of an already exists column.")
	}
	if spec.Position.Type == ColumnPositionFirst {
		position = 0
	} else if spec.Position.Type == ColumnPositionAfter {
		// Find the mentioned column
		c := column.FindCol(cols, spec.Position.RelativeColumn)
		if c == nil {
			return errors.Errorf("No such column: %v", name)
		}
		// insert position is after the mentioned column
		position = c.Offset + 1
	}
	// TODO: Set constraint
	col, _, err := d.buildColumnAndConstraint(position, spec.Column)
	if err != nil {
		return errors.Trace(err)
	}
	// insert col into the right place of the column list
	newCols := make([]*column.Col, 0, len(cols)+1)
	newCols = append(newCols, cols[:position]...)
	newCols = append(newCols, col)
	newCols = append(newCols, cols[position:]...)
	// adjust position
	if position != len(cols) {
		offsetChange := make(map[int]int)
		for i := position + 1; i < len(newCols); i++ {
			offsetChange[newCols[i].Offset] = i
			newCols[i].Offset = i
		}
		// Update index offset info
		for _, idx := range tbl.Indices() {
			for _, c := range idx.Columns {
				newOffset, ok := offsetChange[c.Offset]
				if ok {
					c.Offset = newOffset
				}
			}
		}
	}
	tb := tbl.(*tables.Table)
	tb.Columns = newCols
	// TODO: update index
	// TODO: update default value
	// update infomation schema
	err = d.updateInfoSchema(ctx, schema, tb.Meta())
	return errors.Trace(err)
}
Esempio n. 3
0
func getIndex(t table.Table, name string) *column.IndexedCol {
	for _, idx := range t.Indices() {
		// only public index can be read.

		if len(idx.Columns) == 1 && strings.EqualFold(idx.Columns[0].Name.L, name) {
			return idx
		}
	}
	return nil
}
Esempio n. 4
0
File: ddl.go Progetto: pingcap/tidb
func getAnonymousIndex(t table.Table, colName model.CIStr) model.CIStr {
	id := 2
	l := len(t.Indices())
	indexName := colName
	for i := 0; i < l; i++ {
		if t.Indices()[i].Meta().Name.L == indexName.L {
			indexName = model.NewCIStr(fmt.Sprintf("%s_%d", colName.O, id))
			i = -1
			id++
		}
	}
	return indexName
}
Esempio n. 5
0
// FindIndexByColName implements table.Table FindIndexByColName interface.
func FindIndexByColName(t table.Table, name string) table.Index {
	for _, idx := range t.Indices() {
		// only public index can be read.
		if idx.Meta().State != model.StatePublic {
			continue
		}

		if len(idx.Meta().Columns) == 1 && strings.EqualFold(idx.Meta().Columns[0].Name.L, name) {
			return idx
		}
	}
	return nil
}
Esempio n. 6
0
func checkIndexExists(ctx context.Context, tbl table.Table, indexValue interface{}, handle int64, exists bool) error {
	txn, err := ctx.GetTxn(true)
	if err != nil {
		return errors.Trace(err)
	}
	idx := tbl.Indices()[0]
	doesExist, _, err := idx.Exist(txn, types.MakeDatums(indexValue), handle)
	if err != nil {
		return errors.Trace(err)
	}
	if exists != doesExist {
		if exists {
			return errors.New("index should exists")
		}
		return errors.New("index should not exists")
	}
	return nil
}
Esempio n. 7
0
File: ddl.go Progetto: botvs/tidb
func (d *ddl) deleteTableData(ctx context.Context, t table.Table) error {
	// Remove data.
	err := t.Truncate(ctx)
	if err != nil {
		return errors.Trace(err)
	}
	txn, err := ctx.GetTxn(false)
	if err != nil {
		return errors.Trace(err)
	}
	// Remove indices.
	for _, v := range t.Indices() {
		if v != nil && v.X != nil {
			if err = v.X.Drop(txn); err != nil {
				return errors.Trace(err)
			}
		}
	}

	return nil
}
Esempio n. 8
0
// prefetchIndices uses a BatchPrefetch to load all unique indices that very likely
// will be checked later. The fetched data will be stored in kv cache.
func (s *InsertIntoStmt) prefetchIndices(ctx context.Context, t table.Table, rows [][]interface{}) error {
	var keys []kv.Key
	for _, index := range t.Indices() {
		if !index.Unique {
			continue
		}
		for _, row := range rows {
			colVals, err := index.FetchValues(row)
			if err != nil {
				return errors.Trace(err)
			}
			key, distinct, err := index.X.GenIndexKey(colVals, 0)
			if err != nil {
				return errors.Trace(err)
			}
			if distinct {
				keys = append(keys, key)
			}
		}
	}
	// Only activate if we got more than 1 distinct index.
	if len(keys) <= 1 {
		return nil
	}

	txn, err := ctx.GetTxn(false)
	if err != nil {
		return errors.Trace(err)
	}

	err = txn.BatchPrefetch(keys)
	if err != nil {
		return errors.Trace(err)
	}
	return nil
}
Esempio n. 9
0
File: ddl.go Progetto: botvs/tidb
// Add a column into table
func (d *ddl) addColumn(ctx context.Context, schema *model.DBInfo, tbl table.Table, spec *AlterSpecification, schemaMetaVersion int64) error {
	// Find position
	cols := tbl.Cols()
	position := len(cols)
	name := spec.Column.Name
	// Check column name duplicate.
	dc := column.FindCol(cols, name)
	if dc != nil {
		return errors.Errorf("Try to add a column with the same name of an already exists column.")
	}
	if spec.Position.Type == ColumnPositionFirst {
		position = 0
	} else if spec.Position.Type == ColumnPositionAfter {
		// Find the mentioned column.
		c := column.FindCol(cols, spec.Position.RelativeColumn)
		if c == nil {
			return errors.Errorf("No such column: %v", name)
		}
		// Insert position is after the mentioned column.
		position = c.Offset + 1
	}
	// TODO: set constraint
	col, _, err := d.buildColumnAndConstraint(position, spec.Column)
	if err != nil {
		return errors.Trace(err)
	}
	// insert col into the right place of the column list
	newCols := make([]*column.Col, 0, len(cols)+1)
	newCols = append(newCols, cols[:position]...)
	newCols = append(newCols, col)
	newCols = append(newCols, cols[position:]...)
	// adjust position
	if position != len(cols) {
		offsetChange := make(map[int]int)
		for i := position + 1; i < len(newCols); i++ {
			offsetChange[newCols[i].Offset] = i
			newCols[i].Offset = i
		}
		// Update index offset info
		for _, idx := range tbl.Indices() {
			for _, c := range idx.Columns {
				newOffset, ok := offsetChange[c.Offset]
				if ok {
					c.Offset = newOffset
				}
			}
		}
	}
	tb := tbl.(*tables.Table)
	tb.Columns = newCols

	// TODO: update index
	if err = updateOldRows(ctx, tb, col); err != nil {
		return errors.Trace(err)
	}

	// update infomation schema
	err = kv.RunInNewTxn(d.store, false, func(txn kv.Transaction) error {
		t := meta.NewMeta(txn)
		err := d.verifySchemaMetaVersion(t, schemaMetaVersion)
		if err != nil {
			return errors.Trace(err)
		}

		err = t.UpdateTable(schema.ID, tb.Meta())
		return errors.Trace(err)
	})
	if d.onDDLChange != nil {
		err = d.onDDLChange(err)
	}
	return errors.Trace(err)
}
Esempio n. 10
0
func (s *testIndexChangeSuite) TestIndexChange(c *C) {
	defer testleak.AfterTest(c)()
	d := newDDL(s.store, nil, nil, testLease)
	// create table t (c1 int primary key, c2 int);
	tblInfo := testTableInfo(c, d, "t", 2)
	tblInfo.Columns[0].Flag = mysql.PriKeyFlag | mysql.NotNullFlag
	tblInfo.PKIsHandle = true
	ctx := testNewContext(c, d)
	_, err := ctx.GetTxn(true)
	c.Assert(err, IsNil)
	testCreateTable(c, ctx, d, s.dbInfo, tblInfo)
	originTable := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)

	// insert t values (1, 1), (2, 2), (3, 3)
	_, err = originTable.AddRecord(ctx, types.MakeDatums(1, 1))
	c.Assert(err, IsNil)
	_, err = originTable.AddRecord(ctx, types.MakeDatums(2, 2))
	c.Assert(err, IsNil)
	_, err = originTable.AddRecord(ctx, types.MakeDatums(3, 3))
	c.Assert(err, IsNil)

	err = ctx.CommitTxn()
	c.Assert(err, IsNil)

	tc := &testDDLCallback{}
	// set up hook
	prevState := model.StateNone
	var (
		deleteOnlyTable table.Table
		writeOnlyTable  table.Table
		publicTable     table.Table
		checkErr        error
	)
	tc.onJobUpdated = func(job *model.Job) {
		if job.SchemaState == prevState {
			return
		}
		ctx1 := testNewContext(c, d)
		prevState = job.SchemaState
		var err error
		switch job.SchemaState {
		case model.StateDeleteOnly:
			deleteOnlyTable, err = getCurrentTable(d, s.dbInfo.ID, tblInfo.ID)
			if err != nil {
				checkErr = errors.Trace(err)
			}
		case model.StateWriteOnly:
			writeOnlyTable, err = getCurrentTable(d, s.dbInfo.ID, tblInfo.ID)
			if err != nil {
				checkErr = errors.Trace(err)
			}
			err = s.checkAddWriteOnly(d, ctx1, deleteOnlyTable, writeOnlyTable)
			if err != nil {
				checkErr = errors.Trace(err)
			}
		case model.StatePublic:
			publicTable, err = getCurrentTable(d, s.dbInfo.ID, tblInfo.ID)
			if err != nil {
				checkErr = errors.Trace(err)
			}
			err = s.checkAddPublic(d, ctx1, writeOnlyTable, publicTable)
			if err != nil {
				checkErr = errors.Trace(err)
			}
		}
	}
	d.setHook(tc)
	testCreateIndex(c, ctx, d, s.dbInfo, originTable.Meta(), false, "c2", "c2")
	c.Check(errors.ErrorStack(checkErr), Equals, "")

	d.Stop()
	prevState = model.StatePublic
	var noneTable table.Table
	tc.onJobUpdated = func(job *model.Job) {
		if job.SchemaState == prevState {
			return
		}
		prevState = job.SchemaState
		var err error
		switch job.SchemaState {
		case model.StateWriteOnly:
			writeOnlyTable, err = getCurrentTable(d, s.dbInfo.ID, tblInfo.ID)
			if err != nil {
				checkErr = errors.Trace(err)
			}
			err = s.checkDropWriteOnly(d, ctx, publicTable, writeOnlyTable)
			if err != nil {
				checkErr = errors.Trace(err)
			}
		case model.StateDeleteOnly:
			deleteOnlyTable, err = getCurrentTable(d, s.dbInfo.ID, tblInfo.ID)
			if err != nil {
				checkErr = errors.Trace(err)
			}
			err = s.checkDropDeleteOnly(d, ctx, writeOnlyTable, deleteOnlyTable)
			if err != nil {
				checkErr = errors.Trace(err)
			}
		case model.StateNone:
			noneTable, err = getCurrentTable(d, s.dbInfo.ID, tblInfo.ID)
			if err != nil {
				checkErr = errors.Trace(err)
			}
			if len(noneTable.Indices()) != 0 {
				checkErr = errors.New("index should have been dropped")
			}
		}
	}
	d.start()
	testDropIndex(c, ctx, d, s.dbInfo, publicTable.Meta(), "c2")
	c.Check(errors.ErrorStack(checkErr), Equals, "")
}