Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*: Fix #254 #334

Merged
merged 12 commits into from
Oct 10, 2015
44 changes: 40 additions & 4 deletions ddl/ddl.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ func (d *ddl) AlterTable(ctx context.Context, ident table.Ident, specs []*AlterS
for _, spec := range specs {
switch spec.Action {
case AlterAddColumn:
if err := d.addColumn(ident.Schema, tbl, spec, is.SchemaMetaVersion()); err != nil {
if err := d.addColumn(ctx, ident.Schema, tbl, spec, is.SchemaMetaVersion()); err != nil {
return errors.Trace(err)
}
default:
Expand All @@ -438,7 +438,7 @@ func (d *ddl) AlterTable(ctx context.Context, ident table.Ident, specs []*AlterS
}

// Add a column into table
func (d *ddl) addColumn(schema model.CIStr, tbl table.Table, spec *AlterSpecification, schemaMetaVersion int64) error {
func (d *ddl) addColumn(ctx context.Context, schema model.CIStr, tbl table.Table, spec *AlterSpecification, schemaMetaVersion int64) error {
// Find position
cols := tbl.Cols()
position := len(cols)
Expand Down Expand Up @@ -489,9 +489,11 @@ func (d *ddl) addColumn(schema model.CIStr, tbl table.Table, spec *AlterSpecific
tb := tbl.(*tables.Table)
tb.Columns = newCols
// TODO: update index
// TODO: update default value
// update infomation schema
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 {
err := d.verifySchemaMetaVersion(txn, schemaMetaVersion)
if err != nil {
Expand All @@ -506,6 +508,40 @@ func (d *ddl) addColumn(schema model.CIStr, tbl table.Table, spec *AlterSpecific
return errors.Trace(err)
}

func updateOldRows(ctx context.Context, t *tables.Table, col *column.Col) error {
txn, err := ctx.GetTxn(false)
if err != nil {
return errors.Trace(err)
}
it, err := txn.Seek([]byte(t.FirstKey()), nil)
if err != nil {
return errors.Trace(err)
}
defer it.Close()

prefix := t.KeyPrefix()
for it.Valid() && strings.HasPrefix(it.Key(), prefix) {
handle, err0 := util.DecodeHandleFromRowKey(it.Key())
if err0 != nil {
return errors.Trace(err0)
}
k := t.RecordKey(handle, col)

// TODO: check and get timestamp/datetime default value.
// refer to getDefaultValue in stmt/stmts/stmt_helper.go.
if err0 = t.SetColValue(txn, k, col.DefaultValue); err0 != nil {
return errors.Trace(err0)
}

rk := t.RecordKey(handle, nil)
if it, err0 = kv.NextUntil(it, util.RowKeyPrefixFilter(rk)); err0 != nil {
return errors.Trace(err0)
}
}

return nil
}

// drop table will proceed even if some table in the list does not exists
func (d *ddl) DropTable(ctx context.Context, ti table.Ident) (err error) {
is := d.GetInformationSchema()
Expand Down
41 changes: 39 additions & 2 deletions ddl/ddl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/pingcap/tidb/ddl"
"github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/model"
mysql "github.com/pingcap/tidb/mysqldef"
"github.com/pingcap/tidb/parser"
"github.com/pingcap/tidb/sessionctx"
"github.com/pingcap/tidb/stmt"
Expand Down Expand Up @@ -78,13 +79,49 @@ func (ts *testSuite) TestT(c *C) {
tbStmt = statement("create table t2 (a int unique not null)").(*stmts.CreateTableStmt)
err = sessionctx.GetDomain(ctx).DDL().CreateTable(ctx, tbIdent2, tbStmt.Cols, tbStmt.Constraints)
c.Assert(err, IsNil)
tb, err := sessionctx.GetDomain(ctx).InfoSchema().TableByName(tbIdent2.Schema, tbIdent2.Name)
c.Assert(err, IsNil)
c.Assert(tb, NotNil)
rid0, err := tb.AddRecord(ctx, []interface{}{1})
c.Assert(err, IsNil)
rid1, err := tb.AddRecord(ctx, []interface{}{2})
c.Assert(err, IsNil)
alterStmt := statement(`alter table t2 add b enum("bb") first`).(*stmts.AlterTableStmt)
sessionctx.GetDomain(ctx).DDL().AlterTable(ctx, tbIdent2, alterStmt.Specs)
c.Assert(alterStmt.Specs[0].String(), Not(Equals), "")
cols, err := tb.Row(ctx, rid0)
c.Assert(err, IsNil)
c.Assert(len(cols), Equals, 2)
c.Assert(cols[0], Equals, nil)
c.Assert(cols[1], Equals, int64(1))
alterStmt = statement("alter table t2 add c varchar(255) after b").(*stmts.AlterTableStmt)
sessionctx.GetDomain(ctx).DDL().AlterTable(ctx, tbIdent2, alterStmt.Specs)
c.Assert(alterStmt.Specs[0].String(), Not(Equals), "")
tb, err = sessionctx.GetDomain(ctx).InfoSchema().TableByName(tbIdent2.Schema, tbIdent2.Name)
c.Assert(err, IsNil)
c.Assert(tb, NotNil)
cols, err = tb.Row(ctx, rid1)
c.Assert(err, IsNil)
c.Assert(len(cols), Equals, 3)
c.Assert(cols[0], Equals, nil)
c.Assert(cols[1], Equals, nil)
c.Assert(cols[2], Equals, int64(2))
rid3, err := tb.AddRecord(ctx, []interface{}{mysql.Enum{Name: "bb", Value: 1}, "c", 3})
c.Assert(err, IsNil)
cols, err = tb.Row(ctx, rid3)
c.Assert(err, IsNil)
c.Assert(len(cols), Equals, 3)
c.Assert(cols[0], Equals, mysql.Enum{Name: "bb", Value: 1})
c.Assert(cols[1], Equals, "c")
c.Assert(cols[2], Equals, int64(3))

tb, err := sessionctx.GetDomain(ctx).InfoSchema().TableByName(tbIdent.Schema, tbIdent.Name)
tb, err = sessionctx.GetDomain(ctx).InfoSchema().TableByName(tbIdent.Schema, tbIdent.Name)
c.Assert(err, IsNil)
c.Assert(tb, NotNil)
_, err = tb.AddRecord(ctx, []interface{}{1, "b", 2, 4})
c.Assert(err, IsNil)

alterStmt := statement("alter table t add column aa int first").(*stmts.AlterTableStmt)
alterStmt = statement("alter table t add column aa int first").(*stmts.AlterTableStmt)
sessionctx.GetDomain(ctx).DDL().AlterTable(ctx, tbIdent, alterStmt.Specs)
c.Assert(alterStmt.Specs[0].String(), Not(Equals), "")
// Check indices info
Expand Down
2 changes: 1 addition & 1 deletion domain/domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (do *Domain) loadInfoSchema(txn kv.Transaction) (err error) {
if err != nil {
return
}
log.Info("loadInfoSchema %d", schemaMetaVersion)
log.Infof("loadInfoSchema %d", schemaMetaVersion)
do.infoHandle.Set(schemas, schemaMetaVersion)
return
}
Expand Down
32 changes: 17 additions & 15 deletions table/tables/tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,21 +263,28 @@ func (t *Table) setOnUpdateData(ctx context.Context, touched []bool, data []inte
return nil
}

// SetColValue sets the column value.
// If the column untouched, we don't need to do this.
func (t *Table) SetColValue(txn kv.Transaction, key []byte, data interface{}) error {
v, err := t.EncodeValue(data)
if err != nil {
return errors.Trace(err)
}
if err := txn.Set(key, v); err != nil {
return errors.Trace(err)
}
return nil
}

func (t *Table) setNewData(ctx context.Context, h int64, data []interface{}) error {
txn, err := ctx.GetTxn(false)
if err != nil {
return err
}
for _, col := range t.Cols() {
// set new value
// If column untouched, we do not need to do this
k := t.RecordKey(h, col)
v, err := t.EncodeValue(data[col.Offset])
if err != nil {
return err
}
if err := txn.Set([]byte(k), v); err != nil {
return err
if err := t.SetColValue(txn, k, data[col.Offset]); err != nil {
return errors.Trace(err)
}
}
return nil
Expand Down Expand Up @@ -365,13 +372,8 @@ func (t *Table) AddRecord(ctx context.Context, r []interface{}) (recordID int64,
}
// column key -> column value
for _, c := range t.Cols() {
colKey := t.RecordKey(recordID, c)
data, err := t.EncodeValue(r[c.Offset])
if err != nil {
return 0, err
}
err = txn.Set([]byte(colKey), data)
if err != nil {
k := t.RecordKey(recordID, c)
if err := t.SetColValue(txn, k, r[c.Offset]); err != nil {
return 0, err
}
}
Expand Down