github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/ddl/column_test.go (about)

     1  // Copyright 2015 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package ddl
    15  
    16  import (
    17  	"time"
    18  
    19  	. "github.com/insionng/yougam/libraries/pingcap/check"
    20  	"github.com/insionng/yougam/libraries/pingcap/tidb/ast"
    21  	"github.com/insionng/yougam/libraries/pingcap/tidb/column"
    22  	"github.com/insionng/yougam/libraries/pingcap/tidb/context"
    23  	"github.com/insionng/yougam/libraries/pingcap/tidb/kv"
    24  	"github.com/insionng/yougam/libraries/pingcap/tidb/model"
    25  	"github.com/insionng/yougam/libraries/pingcap/tidb/mysql"
    26  	"github.com/insionng/yougam/libraries/pingcap/tidb/table"
    27  	"github.com/insionng/yougam/libraries/pingcap/tidb/table/tables"
    28  	"github.com/insionng/yougam/libraries/pingcap/tidb/util/mock"
    29  	"github.com/insionng/yougam/libraries/pingcap/tidb/util/testleak"
    30  	"github.com/insionng/yougam/libraries/pingcap/tidb/util/types"
    31  )
    32  
    33  var _ = Suite(&testColumnSuite{})
    34  
    35  type testColumnSuite struct {
    36  	store  kv.Storage
    37  	dbInfo *model.DBInfo
    38  
    39  	d *ddl
    40  }
    41  
    42  func (s *testColumnSuite) SetUpSuite(c *C) {
    43  	trySkipTest(c)
    44  
    45  	s.store = testCreateStore(c, "test_column")
    46  	lease := 50 * time.Millisecond
    47  	s.d = newDDL(s.store, nil, nil, lease)
    48  
    49  	s.dbInfo = testSchemaInfo(c, s.d, "test_column")
    50  	testCreateSchema(c, mock.NewContext(), s.d, s.dbInfo)
    51  }
    52  
    53  func (s *testColumnSuite) TearDownSuite(c *C) {
    54  	trySkipTest(c)
    55  
    56  	testDropSchema(c, mock.NewContext(), s.d, s.dbInfo)
    57  	s.d.close()
    58  
    59  	err := s.store.Close()
    60  	c.Assert(err, IsNil)
    61  }
    62  
    63  func testCreateColumn(c *C, ctx context.Context, d *ddl, dbInfo *model.DBInfo, tblInfo *model.TableInfo,
    64  	colName string, pos *ast.ColumnPosition, defaultValue interface{}) *model.Job {
    65  	col := &model.ColumnInfo{
    66  		Name:         model.NewCIStr(colName),
    67  		Offset:       len(tblInfo.Columns),
    68  		DefaultValue: defaultValue,
    69  	}
    70  
    71  	var err error
    72  	col.ID, err = d.genGlobalID()
    73  	c.Assert(err, IsNil)
    74  
    75  	col.FieldType = *types.NewFieldType(mysql.TypeLong)
    76  
    77  	job := &model.Job{
    78  		SchemaID: dbInfo.ID,
    79  		TableID:  tblInfo.ID,
    80  		Type:     model.ActionAddColumn,
    81  		Args:     []interface{}{col, pos, 0},
    82  	}
    83  
    84  	err = d.doDDLJob(ctx, job)
    85  	c.Assert(err, IsNil)
    86  	return job
    87  }
    88  
    89  func testDropColumn(c *C, ctx context.Context, d *ddl, dbInfo *model.DBInfo, tblInfo *model.TableInfo, colName string, isError bool) *model.Job {
    90  	job := &model.Job{
    91  		SchemaID: dbInfo.ID,
    92  		TableID:  tblInfo.ID,
    93  		Type:     model.ActionDropColumn,
    94  		Args:     []interface{}{model.NewCIStr(colName)},
    95  	}
    96  
    97  	err := d.doDDLJob(ctx, job)
    98  	if isError {
    99  		c.Assert(err, NotNil)
   100  		return nil
   101  	}
   102  
   103  	c.Assert(err, IsNil)
   104  	return job
   105  }
   106  
   107  func (s *testColumnSuite) TestColumn(c *C) {
   108  	defer testleak.AfterTest(c)()
   109  	tblInfo := testTableInfo(c, s.d, "t1", 3)
   110  	ctx := testNewContext(c, s.d)
   111  	defer ctx.FinishTxn(true)
   112  
   113  	testCreateTable(c, ctx, s.d, s.dbInfo, tblInfo)
   114  
   115  	t := testGetTable(c, s.d, s.dbInfo.ID, tblInfo.ID)
   116  
   117  	num := 10
   118  	for i := 0; i < num; i++ {
   119  		_, err := t.AddRecord(ctx, types.MakeDatums(i, 10*i, 100*i))
   120  		c.Assert(err, IsNil)
   121  	}
   122  
   123  	err := ctx.FinishTxn(false)
   124  	c.Assert(err, IsNil)
   125  
   126  	i := int64(0)
   127  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   128  		c.Assert(data, HasLen, 3)
   129  		c.Assert(data[0].GetInt64(), Equals, i)
   130  		c.Assert(data[1].GetInt64(), Equals, 10*i)
   131  		c.Assert(data[2].GetInt64(), Equals, 100*i)
   132  		i++
   133  		return true, nil
   134  	})
   135  	c.Assert(i, Equals, int64(num))
   136  
   137  	c.Assert(column.FindCol(t.Cols(), "c4"), IsNil)
   138  
   139  	job := testCreateColumn(c, ctx, s.d, s.dbInfo, tblInfo, "c4", &ast.ColumnPosition{Tp: ast.ColumnPositionAfter, RelativeColumn: &ast.ColumnName{Name: model.NewCIStr("c3")}}, 100)
   140  	testCheckJobDone(c, s.d, job, true)
   141  
   142  	t = testGetTable(c, s.d, s.dbInfo.ID, tblInfo.ID)
   143  	c.Assert(column.FindCol(t.Cols(), "c4"), NotNil)
   144  
   145  	i = int64(0)
   146  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   147  		c.Assert(data, HasLen, 4)
   148  		c.Assert(data[0].GetInt64(), Equals, i)
   149  		c.Assert(data[1].GetInt64(), Equals, 10*i)
   150  		c.Assert(data[2].GetInt64(), Equals, 100*i)
   151  		c.Assert(data[3].GetInt64(), Equals, int64(100))
   152  		i++
   153  		return true, nil
   154  	})
   155  	c.Assert(i, Equals, int64(num))
   156  
   157  	h, err := t.AddRecord(ctx, types.MakeDatums(11, 12, 13, 14))
   158  	c.Assert(err, IsNil)
   159  	err = ctx.FinishTxn(false)
   160  	c.Assert(err, IsNil)
   161  	values, err := t.RowWithCols(ctx, h, t.Cols())
   162  	c.Assert(err, IsNil)
   163  
   164  	c.Assert(values, HasLen, 4)
   165  	c.Assert(values[3].GetInt64(), Equals, int64(14))
   166  
   167  	job = testDropColumn(c, ctx, s.d, s.dbInfo, tblInfo, "c4", false)
   168  	testCheckJobDone(c, s.d, job, false)
   169  
   170  	t = testGetTable(c, s.d, s.dbInfo.ID, tblInfo.ID)
   171  	values, err = t.RowWithCols(ctx, h, t.Cols())
   172  	c.Assert(err, IsNil)
   173  
   174  	c.Assert(values, HasLen, 3)
   175  	c.Assert(values[2].GetInt64(), Equals, int64(13))
   176  
   177  	job = testCreateColumn(c, ctx, s.d, s.dbInfo, tblInfo, "c4", &ast.ColumnPosition{Tp: ast.ColumnPositionNone}, 111)
   178  	testCheckJobDone(c, s.d, job, true)
   179  
   180  	t = testGetTable(c, s.d, s.dbInfo.ID, tblInfo.ID)
   181  	values, err = t.RowWithCols(ctx, h, t.Cols())
   182  	c.Assert(err, IsNil)
   183  
   184  	c.Assert(values, HasLen, 4)
   185  	c.Assert(values[3].GetInt64(), Equals, int64(111))
   186  
   187  	job = testCreateColumn(c, ctx, s.d, s.dbInfo, tblInfo, "c5", &ast.ColumnPosition{Tp: ast.ColumnPositionNone}, 101)
   188  	testCheckJobDone(c, s.d, job, true)
   189  
   190  	t = testGetTable(c, s.d, s.dbInfo.ID, tblInfo.ID)
   191  	values, err = t.RowWithCols(ctx, h, t.Cols())
   192  	c.Assert(err, IsNil)
   193  
   194  	c.Assert(values, HasLen, 5)
   195  	c.Assert(values[4].GetInt64(), Equals, int64(101))
   196  
   197  	job = testCreateColumn(c, ctx, s.d, s.dbInfo, tblInfo, "c6", &ast.ColumnPosition{Tp: ast.ColumnPositionFirst}, 202)
   198  	testCheckJobDone(c, s.d, job, true)
   199  
   200  	t = testGetTable(c, s.d, s.dbInfo.ID, tblInfo.ID)
   201  	cols := t.Cols()
   202  	c.Assert(cols, HasLen, 6)
   203  	c.Assert(cols[0].Offset, Equals, 0)
   204  	c.Assert(cols[0].Name.L, Equals, "c6")
   205  	c.Assert(cols[1].Offset, Equals, 1)
   206  	c.Assert(cols[1].Name.L, Equals, "c1")
   207  	c.Assert(cols[2].Offset, Equals, 2)
   208  	c.Assert(cols[2].Name.L, Equals, "c2")
   209  	c.Assert(cols[3].Offset, Equals, 3)
   210  	c.Assert(cols[3].Name.L, Equals, "c3")
   211  	c.Assert(cols[4].Offset, Equals, 4)
   212  	c.Assert(cols[4].Name.L, Equals, "c4")
   213  	c.Assert(cols[5].Offset, Equals, 5)
   214  	c.Assert(cols[5].Name.L, Equals, "c5")
   215  
   216  	values, err = t.RowWithCols(ctx, h, cols)
   217  	c.Assert(err, IsNil)
   218  
   219  	c.Assert(values, HasLen, 6)
   220  	c.Assert(values[0].GetInt64(), Equals, int64(202))
   221  	c.Assert(values[5].GetInt64(), Equals, int64(101))
   222  
   223  	job = testDropColumn(c, ctx, s.d, s.dbInfo, tblInfo, "c2", false)
   224  	testCheckJobDone(c, s.d, job, false)
   225  
   226  	t = testGetTable(c, s.d, s.dbInfo.ID, tblInfo.ID)
   227  
   228  	values, err = t.RowWithCols(ctx, h, t.Cols())
   229  	c.Assert(err, IsNil)
   230  
   231  	c.Assert(values, HasLen, 5)
   232  	c.Assert(values[0].GetInt64(), Equals, int64(202))
   233  	c.Assert(values[4].GetInt64(), Equals, int64(101))
   234  
   235  	job = testDropColumn(c, ctx, s.d, s.dbInfo, tblInfo, "c1", false)
   236  	testCheckJobDone(c, s.d, job, false)
   237  
   238  	job = testDropColumn(c, ctx, s.d, s.dbInfo, tblInfo, "c3", false)
   239  	testCheckJobDone(c, s.d, job, false)
   240  
   241  	job = testDropColumn(c, ctx, s.d, s.dbInfo, tblInfo, "c4", false)
   242  	testCheckJobDone(c, s.d, job, false)
   243  
   244  	job = testCreateIndex(c, ctx, s.d, s.dbInfo, tblInfo, false, "c5_idx", "c5")
   245  	testCheckJobDone(c, s.d, job, true)
   246  
   247  	testDropColumn(c, ctx, s.d, s.dbInfo, tblInfo, "c5", true)
   248  
   249  	testDropIndex(c, ctx, s.d, s.dbInfo, tblInfo, "c5_idx")
   250  	testCheckJobDone(c, s.d, job, true)
   251  
   252  	job = testDropColumn(c, ctx, s.d, s.dbInfo, tblInfo, "c5", false)
   253  	testCheckJobDone(c, s.d, job, false)
   254  
   255  	testDropColumn(c, ctx, s.d, s.dbInfo, tblInfo, "c6", true)
   256  
   257  	testDropTable(c, ctx, s.d, s.dbInfo, tblInfo)
   258  }
   259  
   260  func (s *testColumnSuite) checkColumnKVExist(c *C, ctx context.Context, t table.Table, handle int64, col *column.Col, columnValue interface{}, isExist bool) {
   261  	txn, err := ctx.GetTxn(true)
   262  	c.Assert(err, IsNil)
   263  
   264  	key := t.RecordKey(handle, col)
   265  	data, err := txn.Get(key)
   266  
   267  	if isExist {
   268  		c.Assert(err, IsNil)
   269  		v, err1 := tables.DecodeValue(data, &col.FieldType)
   270  		c.Assert(err1, IsNil)
   271  		value, err1 := v.ConvertTo(&col.FieldType)
   272  		c.Assert(err1, IsNil)
   273  		c.Assert(value.GetValue(), Equals, columnValue)
   274  	} else {
   275  		c.Assert(err, NotNil)
   276  	}
   277  
   278  	err = ctx.FinishTxn(false)
   279  	c.Assert(err, IsNil)
   280  }
   281  
   282  func (s *testColumnSuite) checkNoneColumn(c *C, ctx context.Context, d *ddl, tblInfo *model.TableInfo, handle int64, col *column.Col, columnValue interface{}) {
   283  	t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   284  	s.checkColumnKVExist(c, ctx, t, handle, col, columnValue, false)
   285  	s.testGetColumn(c, t, col.Name.L, false)
   286  }
   287  
   288  func (s *testColumnSuite) checkDeleteOnlyColumn(c *C, ctx context.Context, d *ddl, tblInfo *model.TableInfo, handle int64, col *column.Col, row []types.Datum, columnValue interface{}, isDropped bool) {
   289  	t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   290  
   291  	_, err := ctx.GetTxn(true)
   292  	c.Assert(err, IsNil)
   293  
   294  	i := int64(0)
   295  	err = t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   296  		c.Assert(data, DeepEquals, row)
   297  		i++
   298  		return true, nil
   299  	})
   300  	c.Assert(err, IsNil)
   301  	c.Assert(i, Equals, int64(1))
   302  
   303  	s.checkColumnKVExist(c, ctx, t, handle, col, columnValue, isDropped)
   304  
   305  	// Test add a new row.
   306  	_, err = ctx.GetTxn(true)
   307  	c.Assert(err, IsNil)
   308  
   309  	newRow := types.MakeDatums(int64(11), int64(22), int64(33))
   310  	handle, err = t.AddRecord(ctx, newRow)
   311  	c.Assert(err, IsNil)
   312  
   313  	_, err = ctx.GetTxn(true)
   314  	c.Assert(err, IsNil)
   315  
   316  	rows := [][]types.Datum{row, newRow}
   317  
   318  	i = int64(0)
   319  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   320  		c.Assert(data, DeepEquals, rows[i])
   321  		i++
   322  		return true, nil
   323  	})
   324  	c.Assert(i, Equals, int64(2))
   325  
   326  	s.checkColumnKVExist(c, ctx, t, handle, col, columnValue, false)
   327  
   328  	// Test remove a row.
   329  	_, err = ctx.GetTxn(true)
   330  	c.Assert(err, IsNil)
   331  
   332  	err = t.RemoveRecord(ctx, handle, newRow)
   333  	c.Assert(err, IsNil)
   334  
   335  	_, err = ctx.GetTxn(true)
   336  	c.Assert(err, IsNil)
   337  
   338  	i = int64(0)
   339  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   340  		i++
   341  		return true, nil
   342  	})
   343  	c.Assert(i, Equals, int64(1))
   344  
   345  	s.checkColumnKVExist(c, ctx, t, handle, col, columnValue, false)
   346  	s.testGetColumn(c, t, col.Name.L, false)
   347  }
   348  
   349  func (s *testColumnSuite) checkWriteOnlyColumn(c *C, ctx context.Context, d *ddl, tblInfo *model.TableInfo, handle int64, col *column.Col, row []types.Datum, columnValue interface{}, isDropped bool) {
   350  	t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   351  
   352  	_, err := ctx.GetTxn(true)
   353  	c.Assert(err, IsNil)
   354  
   355  	i := int64(0)
   356  	err = t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   357  		c.Assert(data, DeepEquals, row)
   358  		i++
   359  		return true, nil
   360  	})
   361  	c.Assert(err, IsNil)
   362  	c.Assert(i, Equals, int64(1))
   363  
   364  	s.checkColumnKVExist(c, ctx, t, handle, col, columnValue, isDropped)
   365  
   366  	// Test add a new row.
   367  	_, err = ctx.GetTxn(true)
   368  	c.Assert(err, IsNil)
   369  
   370  	newRow := types.MakeDatums(int64(11), int64(22), int64(33))
   371  	handle, err = t.AddRecord(ctx, newRow)
   372  	c.Assert(err, IsNil)
   373  
   374  	_, err = ctx.GetTxn(true)
   375  	c.Assert(err, IsNil)
   376  
   377  	rows := [][]types.Datum{row, newRow}
   378  
   379  	i = int64(0)
   380  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   381  		c.Assert(data, DeepEquals, rows[i])
   382  		i++
   383  		return true, nil
   384  	})
   385  	c.Assert(i, Equals, int64(2))
   386  
   387  	s.checkColumnKVExist(c, ctx, t, handle, col, columnValue, true)
   388  
   389  	// Test remove a row.
   390  	_, err = ctx.GetTxn(true)
   391  	c.Assert(err, IsNil)
   392  
   393  	err = t.RemoveRecord(ctx, handle, newRow)
   394  	c.Assert(err, IsNil)
   395  
   396  	_, err = ctx.GetTxn(true)
   397  	c.Assert(err, IsNil)
   398  
   399  	i = int64(0)
   400  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   401  		i++
   402  		return true, nil
   403  	})
   404  	c.Assert(i, Equals, int64(1))
   405  
   406  	s.checkColumnKVExist(c, ctx, t, handle, col, columnValue, false)
   407  	s.testGetColumn(c, t, col.Name.L, false)
   408  }
   409  
   410  func (s *testColumnSuite) checkReorganizationColumn(c *C, ctx context.Context, d *ddl, tblInfo *model.TableInfo, handle int64, col *column.Col, row []types.Datum, columnValue interface{}, isDropped bool) {
   411  	t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   412  
   413  	_, err := ctx.GetTxn(true)
   414  	c.Assert(err, IsNil)
   415  
   416  	i := int64(0)
   417  	err = t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   418  		c.Assert(data, DeepEquals, row)
   419  		i++
   420  		return true, nil
   421  	})
   422  	c.Assert(err, IsNil)
   423  	c.Assert(i, Equals, int64(1))
   424  
   425  	// Test add a new row.
   426  	_, err = ctx.GetTxn(true)
   427  	c.Assert(err, IsNil)
   428  
   429  	newRow := types.MakeDatums(int64(11), int64(22), int64(33))
   430  	handle, err = t.AddRecord(ctx, newRow)
   431  	c.Assert(err, IsNil)
   432  
   433  	_, err = ctx.GetTxn(true)
   434  	c.Assert(err, IsNil)
   435  
   436  	rows := [][]types.Datum{row, newRow}
   437  
   438  	i = int64(0)
   439  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   440  		c.Assert(data, DeepEquals, rows[i])
   441  		i++
   442  		return true, nil
   443  	})
   444  	c.Assert(i, Equals, int64(2))
   445  
   446  	s.checkColumnKVExist(c, ctx, t, handle, col, columnValue, !isDropped)
   447  
   448  	// Test remove a row.
   449  	_, err = ctx.GetTxn(true)
   450  	c.Assert(err, IsNil)
   451  
   452  	err = t.RemoveRecord(ctx, handle, newRow)
   453  	c.Assert(err, IsNil)
   454  
   455  	_, err = ctx.GetTxn(true)
   456  	c.Assert(err, IsNil)
   457  
   458  	i = int64(0)
   459  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   460  		i++
   461  		return true, nil
   462  	})
   463  	c.Assert(i, Equals, int64(1))
   464  
   465  	s.testGetColumn(c, t, col.Name.L, false)
   466  }
   467  
   468  func (s *testColumnSuite) checkPublicColumn(c *C, ctx context.Context, d *ddl, tblInfo *model.TableInfo, handle int64, col *column.Col, row []types.Datum, columnValue interface{}) {
   469  	t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   470  
   471  	_, err := ctx.GetTxn(true)
   472  	c.Assert(err, IsNil)
   473  
   474  	i := int64(0)
   475  	oldRow := append(row, types.NewDatum(columnValue))
   476  	err = t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   477  		c.Assert(data, DeepEquals, oldRow)
   478  		i++
   479  		return true, nil
   480  	})
   481  	c.Assert(err, IsNil)
   482  	c.Assert(i, Equals, int64(1))
   483  
   484  	// Test add a new row.
   485  	_, err = ctx.GetTxn(true)
   486  	c.Assert(err, IsNil)
   487  
   488  	newRow := types.MakeDatums(int64(11), int64(22), int64(33), int64(44))
   489  	handle, err = t.AddRecord(ctx, newRow)
   490  	c.Assert(err, IsNil)
   491  
   492  	_, err = ctx.GetTxn(true)
   493  	c.Assert(err, IsNil)
   494  
   495  	rows := [][]types.Datum{oldRow, newRow}
   496  
   497  	i = int64(0)
   498  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   499  		c.Assert(data, DeepEquals, rows[i])
   500  		i++
   501  		return true, nil
   502  	})
   503  	c.Assert(i, Equals, int64(2))
   504  
   505  	// Test remove a row.
   506  	_, err = ctx.GetTxn(true)
   507  	c.Assert(err, IsNil)
   508  
   509  	err = t.RemoveRecord(ctx, handle, newRow)
   510  	c.Assert(err, IsNil)
   511  
   512  	_, err = ctx.GetTxn(true)
   513  	c.Assert(err, IsNil)
   514  
   515  	i = int64(0)
   516  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   517  		c.Assert(data, DeepEquals, oldRow)
   518  		i++
   519  		return true, nil
   520  	})
   521  	c.Assert(i, Equals, int64(1))
   522  
   523  	err = ctx.FinishTxn(false)
   524  	c.Assert(err, IsNil)
   525  	s.testGetColumn(c, t, col.Name.L, true)
   526  }
   527  
   528  func (s *testColumnSuite) checkAddOrDropColumn(c *C, state model.SchemaState, d *ddl, tblInfo *model.TableInfo, handle int64, col *column.Col, row []types.Datum, columnValue interface{}, isDropped bool) {
   529  	ctx := testNewContext(c, d)
   530  
   531  	switch state {
   532  	case model.StateNone:
   533  		s.checkNoneColumn(c, ctx, d, tblInfo, handle, col, columnValue)
   534  	case model.StateDeleteOnly:
   535  		s.checkDeleteOnlyColumn(c, ctx, d, tblInfo, handle, col, row, columnValue, isDropped)
   536  	case model.StateWriteOnly:
   537  		s.checkWriteOnlyColumn(c, ctx, d, tblInfo, handle, col, row, columnValue, isDropped)
   538  	case model.StateWriteReorganization, model.StateDeleteReorganization:
   539  		s.checkReorganizationColumn(c, ctx, d, tblInfo, handle, col, row, columnValue, isDropped)
   540  	case model.StatePublic:
   541  		s.checkPublicColumn(c, ctx, d, tblInfo, handle, col, row, columnValue)
   542  	}
   543  }
   544  
   545  func (s *testColumnSuite) testGetColumn(c *C, t table.Table, name string, isExist bool) {
   546  	col := column.FindCol(t.Cols(), name)
   547  	if isExist {
   548  		c.Assert(col, NotNil)
   549  	} else {
   550  		c.Assert(col, IsNil)
   551  	}
   552  }
   553  
   554  func (s *testColumnSuite) TestAddColumn(c *C) {
   555  	defer testleak.AfterTest(c)()
   556  	d := newDDL(s.store, nil, nil, 100*time.Millisecond)
   557  	tblInfo := testTableInfo(c, d, "t", 3)
   558  	ctx := testNewContext(c, d)
   559  
   560  	_, err := ctx.GetTxn(true)
   561  	c.Assert(err, IsNil)
   562  
   563  	testCreateTable(c, ctx, d, s.dbInfo, tblInfo)
   564  
   565  	t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   566  
   567  	row := types.MakeDatums(int64(1), int64(2), int64(3))
   568  	handle, err := t.AddRecord(ctx, row)
   569  	c.Assert(err, IsNil)
   570  
   571  	err = ctx.FinishTxn(false)
   572  	c.Assert(err, IsNil)
   573  
   574  	colName := "c4"
   575  	defaultColValue := int64(4)
   576  	checkOK := false
   577  
   578  	tc := &testDDLCallback{}
   579  	tc.onJobUpdated = func(job *model.Job) {
   580  		if checkOK {
   581  			return
   582  		}
   583  
   584  		t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID).(*tables.Table)
   585  		col := column.FindCol(t.Columns, colName)
   586  		if col == nil {
   587  			return
   588  		}
   589  
   590  		s.checkAddOrDropColumn(c, col.State, d, tblInfo, handle, col, row, defaultColValue, false)
   591  
   592  		if col.State == model.StatePublic {
   593  			checkOK = true
   594  		}
   595  	}
   596  
   597  	d.hook = tc
   598  
   599  	// Use local ddl for callback test.
   600  	s.d.close()
   601  
   602  	d.close()
   603  	d.start()
   604  
   605  	job := testCreateColumn(c, ctx, d, s.dbInfo, tblInfo, colName, &ast.ColumnPosition{Tp: ast.ColumnPositionNone}, defaultColValue)
   606  	testCheckJobDone(c, d, job, true)
   607  
   608  	_, err = ctx.GetTxn(true)
   609  	c.Assert(err, IsNil)
   610  
   611  	job = testDropTable(c, ctx, d, s.dbInfo, tblInfo)
   612  	testCheckJobDone(c, d, job, false)
   613  
   614  	err = ctx.FinishTxn(false)
   615  	c.Assert(err, IsNil)
   616  
   617  	d.close()
   618  	s.d.start()
   619  }
   620  
   621  func (s *testColumnSuite) TestDropColumn(c *C) {
   622  	defer testleak.AfterTest(c)()
   623  	d := newDDL(s.store, nil, nil, 100*time.Millisecond)
   624  	tblInfo := testTableInfo(c, d, "t", 4)
   625  	ctx := testNewContext(c, d)
   626  
   627  	_, err := ctx.GetTxn(true)
   628  	c.Assert(err, IsNil)
   629  
   630  	testCreateTable(c, ctx, d, s.dbInfo, tblInfo)
   631  
   632  	t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   633  
   634  	colName := "c4"
   635  	defaultColValue := int64(4)
   636  	row := types.MakeDatums(int64(1), int64(2), int64(3))
   637  	handle, err := t.AddRecord(ctx, append(row, types.NewDatum(defaultColValue)))
   638  	c.Assert(err, IsNil)
   639  
   640  	err = ctx.FinishTxn(false)
   641  	c.Assert(err, IsNil)
   642  
   643  	checkOK := false
   644  	oldCol := &column.Col{}
   645  
   646  	tc := &testDDLCallback{}
   647  	tc.onJobUpdated = func(job *model.Job) {
   648  		if checkOK {
   649  			return
   650  		}
   651  
   652  		t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID).(*tables.Table)
   653  		col := column.FindCol(t.Columns, colName)
   654  		if col == nil {
   655  			s.checkAddOrDropColumn(c, model.StateNone, d, tblInfo, handle, oldCol, row, defaultColValue, true)
   656  			checkOK = true
   657  			return
   658  		}
   659  
   660  		s.checkAddOrDropColumn(c, col.State, d, tblInfo, handle, col, row, defaultColValue, true)
   661  		oldCol = col
   662  	}
   663  
   664  	d.hook = tc
   665  
   666  	// Use local ddl for callback test.
   667  	s.d.close()
   668  
   669  	d.close()
   670  	d.start()
   671  
   672  	job := testDropColumn(c, ctx, s.d, s.dbInfo, tblInfo, colName, false)
   673  	testCheckJobDone(c, d, job, false)
   674  
   675  	_, err = ctx.GetTxn(true)
   676  	c.Assert(err, IsNil)
   677  
   678  	job = testDropTable(c, ctx, d, s.dbInfo, tblInfo)
   679  	testCheckJobDone(c, d, job, false)
   680  
   681  	err = ctx.FinishTxn(false)
   682  	c.Assert(err, IsNil)
   683  
   684  	d.close()
   685  	s.d.start()
   686  }