github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/ddl/index_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  	"strings"
    18  	"time"
    19  
    20  	. "github.com/insionng/yougam/libraries/pingcap/check"
    21  	"github.com/insionng/yougam/libraries/pingcap/tidb/ast"
    22  	"github.com/insionng/yougam/libraries/pingcap/tidb/column"
    23  	"github.com/insionng/yougam/libraries/pingcap/tidb/context"
    24  	"github.com/insionng/yougam/libraries/pingcap/tidb/kv"
    25  	"github.com/insionng/yougam/libraries/pingcap/tidb/model"
    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(&testIndexSuite{})
    34  
    35  type testIndexSuite struct {
    36  	store  kv.Storage
    37  	dbInfo *model.DBInfo
    38  
    39  	d *ddl
    40  }
    41  
    42  func (s *testIndexSuite) SetUpSuite(c *C) {
    43  	trySkipTest(c)
    44  
    45  	s.store = testCreateStore(c, "test_index")
    46  	lease := 50 * time.Millisecond
    47  	s.d = newDDL(s.store, nil, nil, lease)
    48  
    49  	s.dbInfo = testSchemaInfo(c, s.d, "test_index")
    50  	testCreateSchema(c, mock.NewContext(), s.d, s.dbInfo)
    51  }
    52  
    53  func (s *testIndexSuite) 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 testCreateIndex(c *C, ctx context.Context, d *ddl, dbInfo *model.DBInfo, tblInfo *model.TableInfo, unique bool, indexName string, colName string) *model.Job {
    64  	id, err := d.genGlobalID()
    65  	c.Assert(err, IsNil)
    66  	job := &model.Job{
    67  		SchemaID: dbInfo.ID,
    68  		TableID:  tblInfo.ID,
    69  		Type:     model.ActionAddIndex,
    70  		Args:     []interface{}{unique, model.NewCIStr(indexName), id, []*ast.IndexColName{{Column: &ast.ColumnName{Name: model.NewCIStr(colName)}, Length: 256}}},
    71  	}
    72  
    73  	err = d.doDDLJob(ctx, job)
    74  	c.Assert(err, IsNil)
    75  	return job
    76  }
    77  
    78  func testDropIndex(c *C, ctx context.Context, d *ddl, dbInfo *model.DBInfo, tblInfo *model.TableInfo, indexName string) *model.Job {
    79  	job := &model.Job{
    80  		SchemaID: dbInfo.ID,
    81  		TableID:  tblInfo.ID,
    82  		Type:     model.ActionDropIndex,
    83  		Args:     []interface{}{model.NewCIStr(indexName)},
    84  	}
    85  
    86  	err := d.doDDLJob(ctx, job)
    87  	c.Assert(err, IsNil)
    88  	return job
    89  }
    90  
    91  func (s *testIndexSuite) TestIndex(c *C) {
    92  	defer testleak.AfterTest(c)()
    93  	tblInfo := testTableInfo(c, s.d, "t1", 3)
    94  	ctx := testNewContext(c, s.d)
    95  	defer ctx.FinishTxn(true)
    96  
    97  	txn, err := ctx.GetTxn(true)
    98  	c.Assert(err, IsNil)
    99  
   100  	testCreateTable(c, ctx, s.d, s.dbInfo, tblInfo)
   101  
   102  	t := testGetTable(c, s.d, s.dbInfo.ID, tblInfo.ID)
   103  
   104  	num := 10
   105  	for i := 0; i < num; i++ {
   106  		_, err = t.AddRecord(ctx, types.MakeDatums(i, i, i))
   107  		c.Assert(err, IsNil)
   108  	}
   109  
   110  	err = ctx.FinishTxn(false)
   111  	c.Assert(err, IsNil)
   112  
   113  	i := int64(0)
   114  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   115  		c.Assert(data[0].GetInt64(), Equals, i)
   116  		i++
   117  		return true, nil
   118  	})
   119  
   120  	job := testCreateIndex(c, ctx, s.d, s.dbInfo, tblInfo, true, "c1_uni", "c1")
   121  	testCheckJobDone(c, s.d, job, true)
   122  
   123  	t = testGetTable(c, s.d, s.dbInfo.ID, tblInfo.ID)
   124  	index := tables.FindIndexByColName(t, "c1")
   125  	c.Assert(index, NotNil)
   126  
   127  	h, err := t.AddRecord(ctx, types.MakeDatums(num+1, 1, 1))
   128  	c.Assert(err, IsNil)
   129  
   130  	h1, err := t.AddRecord(ctx, types.MakeDatums(num+1, 1, 1))
   131  	c.Assert(err, NotNil)
   132  	c.Assert(h, Equals, h1)
   133  
   134  	h, err = t.AddRecord(ctx, types.MakeDatums(1, 1, 1))
   135  	c.Assert(err, NotNil)
   136  
   137  	txn, err = ctx.GetTxn(true)
   138  	c.Assert(err, IsNil)
   139  
   140  	exist, _, err := index.X.Exist(txn, types.MakeDatums(1), h)
   141  	c.Assert(err, IsNil)
   142  	c.Assert(exist, IsTrue)
   143  
   144  	job = testDropIndex(c, ctx, s.d, s.dbInfo, tblInfo, "c1_uni")
   145  	testCheckJobDone(c, s.d, job, false)
   146  
   147  	t = testGetTable(c, s.d, s.dbInfo.ID, tblInfo.ID)
   148  	index1 := tables.FindIndexByColName(t, "c1")
   149  	c.Assert(index1, IsNil)
   150  
   151  	txn, err = ctx.GetTxn(true)
   152  	c.Assert(err, IsNil)
   153  
   154  	exist, _, err = index.X.Exist(txn, types.MakeDatums(1), h)
   155  	c.Assert(err, IsNil)
   156  	c.Assert(exist, IsFalse)
   157  
   158  	_, err = t.AddRecord(ctx, types.MakeDatums(1, 1, 1))
   159  	c.Assert(err, IsNil)
   160  }
   161  
   162  func getIndex(t table.Table, name string) *column.IndexedCol {
   163  	for _, idx := range t.Indices() {
   164  		// only public index can be read.
   165  
   166  		if len(idx.Columns) == 1 && strings.EqualFold(idx.Columns[0].Name.L, name) {
   167  			return idx
   168  		}
   169  	}
   170  	return nil
   171  }
   172  
   173  func (s *testIndexSuite) testGetIndex(c *C, t table.Table, name string, isExist bool) {
   174  	index := tables.FindIndexByColName(t, name)
   175  	if isExist {
   176  		c.Assert(index, NotNil)
   177  	} else {
   178  		c.Assert(index, IsNil)
   179  	}
   180  }
   181  
   182  func (s *testIndexSuite) checkIndexKVExist(c *C, ctx context.Context, t table.Table, handle int64, indexCol *column.IndexedCol, columnValues []types.Datum, isExist bool) {
   183  	c.Assert(len(indexCol.Columns), Equals, len(columnValues))
   184  
   185  	txn, err := ctx.GetTxn(true)
   186  	c.Assert(err, IsNil)
   187  
   188  	exist, _, err := indexCol.X.Exist(txn, columnValues, handle)
   189  	c.Assert(err, IsNil)
   190  	c.Assert(exist, Equals, isExist)
   191  
   192  	err = ctx.FinishTxn(false)
   193  	c.Assert(err, IsNil)
   194  }
   195  
   196  func (s *testIndexSuite) checkNoneIndex(c *C, ctx context.Context, d *ddl, tblInfo *model.TableInfo, handle int64, indexCol *column.IndexedCol, row []types.Datum) {
   197  	t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   198  
   199  	columnValues := make([]types.Datum, len(indexCol.Columns))
   200  	for i, column := range indexCol.Columns {
   201  		columnValues[i] = row[column.Offset]
   202  	}
   203  
   204  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, false)
   205  	s.testGetIndex(c, t, indexCol.Columns[0].Name.L, false)
   206  }
   207  
   208  func (s *testIndexSuite) checkDeleteOnlyIndex(c *C, ctx context.Context, d *ddl, tblInfo *model.TableInfo, handle int64, indexCol *column.IndexedCol, row []types.Datum, isDropped bool) {
   209  	t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   210  
   211  	_, err := ctx.GetTxn(true)
   212  	c.Assert(err, IsNil)
   213  
   214  	i := int64(0)
   215  	err = t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   216  		c.Assert(data, DeepEquals, row)
   217  		i++
   218  		return true, nil
   219  	})
   220  	c.Assert(err, IsNil)
   221  	c.Assert(i, Equals, int64(1))
   222  
   223  	columnValues := make([]types.Datum, len(indexCol.Columns))
   224  	for i, column := range indexCol.Columns {
   225  		columnValues[i] = row[column.Offset]
   226  	}
   227  
   228  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, isDropped)
   229  
   230  	// Test add a new row.
   231  	_, err = ctx.GetTxn(true)
   232  	c.Assert(err, IsNil)
   233  
   234  	newRow := types.MakeDatums(int64(11), int64(22), int64(33))
   235  	handle, err = t.AddRecord(ctx, newRow)
   236  	c.Assert(err, IsNil)
   237  
   238  	_, err = ctx.GetTxn(true)
   239  	c.Assert(err, IsNil)
   240  
   241  	rows := [][]types.Datum{row, newRow}
   242  
   243  	i = int64(0)
   244  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   245  		c.Assert(data, DeepEquals, rows[i])
   246  		i++
   247  		return true, nil
   248  	})
   249  	c.Assert(i, Equals, int64(2))
   250  
   251  	for i, column := range indexCol.Columns {
   252  		columnValues[i] = newRow[column.Offset]
   253  	}
   254  
   255  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, false)
   256  
   257  	// Test update a new row.
   258  	_, err = ctx.GetTxn(true)
   259  	c.Assert(err, IsNil)
   260  
   261  	newUpdateRow := types.MakeDatums(int64(44), int64(55), int64(66))
   262  	touched := map[int]bool{0: true, 1: true, 2: true}
   263  	err = t.UpdateRecord(ctx, handle, newRow, newUpdateRow, touched)
   264  	c.Assert(err, IsNil)
   265  
   266  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, false)
   267  
   268  	for i, column := range indexCol.Columns {
   269  		columnValues[i] = newUpdateRow[column.Offset]
   270  	}
   271  
   272  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, false)
   273  
   274  	// Test remove a row.
   275  	_, err = ctx.GetTxn(true)
   276  	c.Assert(err, IsNil)
   277  
   278  	err = t.RemoveRecord(ctx, handle, newUpdateRow)
   279  	c.Assert(err, IsNil)
   280  
   281  	_, err = ctx.GetTxn(true)
   282  	c.Assert(err, IsNil)
   283  
   284  	i = int64(0)
   285  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   286  		i++
   287  		return true, nil
   288  	})
   289  	c.Assert(i, Equals, int64(1))
   290  
   291  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, false)
   292  	s.testGetIndex(c, t, indexCol.Columns[0].Name.L, false)
   293  }
   294  
   295  func (s *testIndexSuite) checkWriteOnlyIndex(c *C, ctx context.Context, d *ddl, tblInfo *model.TableInfo, handle int64, indexCol *column.IndexedCol, row []types.Datum, isDropped bool) {
   296  	t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   297  
   298  	_, err := ctx.GetTxn(true)
   299  	c.Assert(err, IsNil)
   300  
   301  	i := int64(0)
   302  	err = t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   303  		c.Assert(data, DeepEquals, row)
   304  		i++
   305  		return true, nil
   306  	})
   307  	c.Assert(err, IsNil)
   308  	c.Assert(i, Equals, int64(1))
   309  
   310  	columnValues := make([]types.Datum, len(indexCol.Columns))
   311  	for i, column := range indexCol.Columns {
   312  		columnValues[i] = row[column.Offset]
   313  	}
   314  
   315  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, isDropped)
   316  
   317  	// Test add a new row.
   318  	_, err = ctx.GetTxn(true)
   319  	c.Assert(err, IsNil)
   320  
   321  	newRow := types.MakeDatums(int64(11), int64(22), int64(33))
   322  	handle, err = t.AddRecord(ctx, newRow)
   323  	c.Assert(err, IsNil)
   324  
   325  	_, err = ctx.GetTxn(true)
   326  	c.Assert(err, IsNil)
   327  
   328  	rows := [][]types.Datum{row, newRow}
   329  
   330  	i = int64(0)
   331  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   332  		c.Assert(data, DeepEquals, rows[i])
   333  		i++
   334  		return true, nil
   335  	})
   336  	c.Assert(i, Equals, int64(2))
   337  
   338  	for i, column := range indexCol.Columns {
   339  		columnValues[i] = newRow[column.Offset]
   340  	}
   341  
   342  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, true)
   343  
   344  	// Test update a new row.
   345  	_, err = ctx.GetTxn(true)
   346  	c.Assert(err, IsNil)
   347  
   348  	newUpdateRow := types.MakeDatums(int64(44), int64(55), int64(66))
   349  	touched := map[int]bool{0: true, 1: true, 2: true}
   350  	err = t.UpdateRecord(ctx, handle, newRow, newUpdateRow, touched)
   351  	c.Assert(err, IsNil)
   352  
   353  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, false)
   354  
   355  	for i, column := range indexCol.Columns {
   356  		columnValues[i] = newUpdateRow[column.Offset]
   357  	}
   358  
   359  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, true)
   360  
   361  	// Test remove a row.
   362  	_, err = ctx.GetTxn(true)
   363  	c.Assert(err, IsNil)
   364  
   365  	err = t.RemoveRecord(ctx, handle, newUpdateRow)
   366  	c.Assert(err, IsNil)
   367  
   368  	_, err = ctx.GetTxn(true)
   369  	c.Assert(err, IsNil)
   370  
   371  	i = int64(0)
   372  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   373  		i++
   374  		return true, nil
   375  	})
   376  	c.Assert(i, Equals, int64(1))
   377  
   378  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, false)
   379  	s.testGetIndex(c, t, indexCol.Columns[0].Name.L, false)
   380  }
   381  
   382  func (s *testIndexSuite) checkReorganizationIndex(c *C, ctx context.Context, d *ddl, tblInfo *model.TableInfo, handle int64, indexCol *column.IndexedCol, row []types.Datum, isDropped bool) {
   383  	t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   384  
   385  	_, err := ctx.GetTxn(true)
   386  	c.Assert(err, IsNil)
   387  
   388  	i := int64(0)
   389  	err = t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   390  		c.Assert(data, DeepEquals, row)
   391  		i++
   392  		return true, nil
   393  	})
   394  	c.Assert(err, IsNil)
   395  	c.Assert(i, Equals, int64(1))
   396  
   397  	// Test add a new row.
   398  	_, err = ctx.GetTxn(true)
   399  	c.Assert(err, IsNil)
   400  
   401  	newRow := types.MakeDatums(int64(11), int64(22), int64(33))
   402  	handle, err = t.AddRecord(ctx, newRow)
   403  	c.Assert(err, IsNil)
   404  
   405  	_, err = ctx.GetTxn(true)
   406  	c.Assert(err, IsNil)
   407  
   408  	rows := [][]types.Datum{row, newRow}
   409  
   410  	i = int64(0)
   411  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   412  		c.Assert(data, DeepEquals, rows[i])
   413  		i++
   414  		return true, nil
   415  	})
   416  	c.Assert(i, Equals, int64(2))
   417  
   418  	columnValues := make([]types.Datum, len(indexCol.Columns))
   419  	for i, column := range indexCol.Columns {
   420  		columnValues[i] = newRow[column.Offset]
   421  	}
   422  
   423  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, !isDropped)
   424  
   425  	// Test update a new row.
   426  	_, err = ctx.GetTxn(true)
   427  	c.Assert(err, IsNil)
   428  
   429  	newUpdateRow := types.MakeDatums(int64(44), int64(55), int64(66))
   430  	touched := map[int]bool{0: true, 1: true, 2: true}
   431  	err = t.UpdateRecord(ctx, handle, newRow, newUpdateRow, touched)
   432  	c.Assert(err, IsNil)
   433  
   434  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, false)
   435  
   436  	for i, column := range indexCol.Columns {
   437  		columnValues[i] = newUpdateRow[column.Offset]
   438  	}
   439  
   440  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, !isDropped)
   441  
   442  	// Test remove a row.
   443  	_, err = ctx.GetTxn(true)
   444  	c.Assert(err, IsNil)
   445  
   446  	err = t.RemoveRecord(ctx, handle, newUpdateRow)
   447  	c.Assert(err, IsNil)
   448  
   449  	_, err = ctx.GetTxn(true)
   450  	c.Assert(err, IsNil)
   451  
   452  	i = int64(0)
   453  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   454  		i++
   455  		return true, nil
   456  	})
   457  	c.Assert(i, Equals, int64(1))
   458  
   459  	s.testGetIndex(c, t, indexCol.Columns[0].Name.L, false)
   460  }
   461  
   462  func (s *testIndexSuite) checkPublicIndex(c *C, ctx context.Context, d *ddl, tblInfo *model.TableInfo, handle int64, indexCol *column.IndexedCol, row []types.Datum) {
   463  	t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   464  
   465  	_, err := ctx.GetTxn(true)
   466  	c.Assert(err, IsNil)
   467  
   468  	i := int64(0)
   469  	err = t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   470  		c.Assert(data, DeepEquals, row)
   471  		i++
   472  		return true, nil
   473  	})
   474  	c.Assert(err, IsNil)
   475  	c.Assert(i, Equals, int64(1))
   476  
   477  	columnValues := make([]types.Datum, len(indexCol.Columns))
   478  	for i, column := range indexCol.Columns {
   479  		columnValues[i] = row[column.Offset]
   480  	}
   481  
   482  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, true)
   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))
   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{row, 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  	for i, column := range indexCol.Columns {
   506  		columnValues[i] = newRow[column.Offset]
   507  	}
   508  
   509  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, true)
   510  
   511  	// Test update a new row.
   512  	_, err = ctx.GetTxn(true)
   513  	c.Assert(err, IsNil)
   514  
   515  	newUpdateRow := types.MakeDatums(int64(44), int64(55), int64(66))
   516  	touched := map[int]bool{0: true, 1: true, 2: true}
   517  	err = t.UpdateRecord(ctx, handle, newRow, newUpdateRow, touched)
   518  	c.Assert(err, IsNil)
   519  
   520  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, false)
   521  
   522  	for i, column := range indexCol.Columns {
   523  		columnValues[i] = newUpdateRow[column.Offset]
   524  	}
   525  
   526  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, true)
   527  
   528  	// Test remove a row.
   529  	_, err = ctx.GetTxn(true)
   530  	c.Assert(err, IsNil)
   531  
   532  	err = t.RemoveRecord(ctx, handle, newUpdateRow)
   533  	c.Assert(err, IsNil)
   534  
   535  	_, err = ctx.GetTxn(true)
   536  	c.Assert(err, IsNil)
   537  
   538  	i = int64(0)
   539  	t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   540  		i++
   541  		return true, nil
   542  	})
   543  	c.Assert(i, Equals, int64(1))
   544  
   545  	s.checkIndexKVExist(c, ctx, t, handle, indexCol, columnValues, false)
   546  	s.testGetIndex(c, t, indexCol.Columns[0].Name.L, true)
   547  }
   548  
   549  func (s *testIndexSuite) checkAddOrDropIndex(c *C, state model.SchemaState, d *ddl, tblInfo *model.TableInfo, handle int64, indexCol *column.IndexedCol, row []types.Datum, isDropped bool) {
   550  	ctx := testNewContext(c, d)
   551  
   552  	switch state {
   553  	case model.StateNone:
   554  		s.checkNoneIndex(c, ctx, d, tblInfo, handle, indexCol, row)
   555  	case model.StateDeleteOnly:
   556  		s.checkDeleteOnlyIndex(c, ctx, d, tblInfo, handle, indexCol, row, isDropped)
   557  	case model.StateWriteOnly:
   558  		s.checkWriteOnlyIndex(c, ctx, d, tblInfo, handle, indexCol, row, isDropped)
   559  	case model.StateWriteReorganization, model.StateDeleteReorganization:
   560  		s.checkReorganizationIndex(c, ctx, d, tblInfo, handle, indexCol, row, isDropped)
   561  	case model.StatePublic:
   562  		s.checkPublicIndex(c, ctx, d, tblInfo, handle, indexCol, row)
   563  	}
   564  }
   565  
   566  func (s *testIndexSuite) TestAddIndex(c *C) {
   567  	defer testleak.AfterTest(c)()
   568  	d := newDDL(s.store, nil, nil, 100*time.Millisecond)
   569  	tblInfo := testTableInfo(c, d, "t", 3)
   570  	ctx := testNewContext(c, d)
   571  
   572  	_, err := ctx.GetTxn(true)
   573  	c.Assert(err, IsNil)
   574  
   575  	testCreateTable(c, ctx, d, s.dbInfo, tblInfo)
   576  
   577  	t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   578  
   579  	row := types.MakeDatums(int64(1), int64(2), int64(3))
   580  	handle, err := t.AddRecord(ctx, row)
   581  	c.Assert(err, IsNil)
   582  
   583  	err = ctx.FinishTxn(false)
   584  	c.Assert(err, IsNil)
   585  
   586  	checkOK := false
   587  
   588  	tc := &testDDLCallback{}
   589  	tc.onJobUpdated = func(job *model.Job) {
   590  		if checkOK {
   591  			return
   592  		}
   593  
   594  		t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   595  		indexCol := getIndex(t, "c1")
   596  		if indexCol == nil {
   597  			return
   598  		}
   599  
   600  		s.checkAddOrDropIndex(c, indexCol.State, d, tblInfo, handle, indexCol, row, false)
   601  
   602  		if indexCol.State == model.StatePublic {
   603  			checkOK = true
   604  		}
   605  	}
   606  
   607  	d.hook = tc
   608  
   609  	// Use local ddl for callback test.
   610  	s.d.close()
   611  
   612  	d.close()
   613  	d.start()
   614  
   615  	job := testCreateIndex(c, ctx, d, s.dbInfo, tblInfo, true, "c1_uni", "c1")
   616  	testCheckJobDone(c, d, job, true)
   617  
   618  	job = testCreateIndex(c, ctx, d, s.dbInfo, tblInfo, true, "c1", "c1")
   619  	testCheckJobDone(c, d, job, true)
   620  
   621  	_, err = ctx.GetTxn(true)
   622  	c.Assert(err, IsNil)
   623  
   624  	job = testDropTable(c, ctx, d, s.dbInfo, tblInfo)
   625  	testCheckJobDone(c, d, job, false)
   626  
   627  	err = ctx.FinishTxn(false)
   628  	c.Assert(err, IsNil)
   629  
   630  	d.close()
   631  	s.d.start()
   632  }
   633  
   634  func (s *testIndexSuite) TestDropIndex(c *C) {
   635  	defer testleak.AfterTest(c)()
   636  	d := newDDL(s.store, nil, nil, 100*time.Millisecond)
   637  	tblInfo := testTableInfo(c, d, "t", 3)
   638  	ctx := testNewContext(c, d)
   639  
   640  	_, err := ctx.GetTxn(true)
   641  	c.Assert(err, IsNil)
   642  
   643  	testCreateTable(c, ctx, d, s.dbInfo, tblInfo)
   644  
   645  	t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   646  
   647  	row := types.MakeDatums(int64(1), int64(2), int64(3))
   648  	handle, err := t.AddRecord(ctx, row)
   649  	c.Assert(err, IsNil)
   650  
   651  	err = ctx.FinishTxn(false)
   652  	c.Assert(err, IsNil)
   653  
   654  	job := testCreateIndex(c, ctx, s.d, s.dbInfo, tblInfo, true, "c1_uni", "c1")
   655  	testCheckJobDone(c, d, job, true)
   656  
   657  	err = ctx.FinishTxn(false)
   658  	c.Assert(err, IsNil)
   659  
   660  	checkOK := false
   661  	oldIndexCol := &column.IndexedCol{}
   662  
   663  	tc := &testDDLCallback{}
   664  	tc.onJobUpdated = func(job *model.Job) {
   665  		if checkOK {
   666  			return
   667  		}
   668  
   669  		t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   670  		indexCol := getIndex(t, "c1")
   671  		if indexCol == nil {
   672  			s.checkAddOrDropIndex(c, model.StateNone, d, tblInfo, handle, oldIndexCol, row, true)
   673  			checkOK = true
   674  			return
   675  		}
   676  
   677  		s.checkAddOrDropIndex(c, indexCol.State, d, tblInfo, handle, indexCol, row, true)
   678  		oldIndexCol = indexCol
   679  	}
   680  
   681  	d.hook = tc
   682  
   683  	// Use local ddl for callback test.
   684  	s.d.close()
   685  
   686  	d.close()
   687  	d.start()
   688  
   689  	job = testDropIndex(c, ctx, d, s.dbInfo, tblInfo, "c1_uni")
   690  	testCheckJobDone(c, d, job, false)
   691  
   692  	_, err = ctx.GetTxn(true)
   693  	c.Assert(err, IsNil)
   694  
   695  	job = testDropTable(c, ctx, d, s.dbInfo, tblInfo)
   696  	testCheckJobDone(c, d, job, false)
   697  
   698  	err = ctx.FinishTxn(false)
   699  	c.Assert(err, IsNil)
   700  
   701  	d.close()
   702  	s.d.start()
   703  }
   704  
   705  func (s *testIndexSuite) TestAddIndexWithNullColumn(c *C) {
   706  	defer testleak.AfterTest(c)()
   707  	d := newDDL(s.store, nil, nil, 100*time.Millisecond)
   708  	tblInfo := testTableInfo(c, d, "t", 3)
   709  	// Change c2.DefaultValue to nil
   710  	tblInfo.Columns[1].DefaultValue = nil
   711  	ctx := testNewContext(c, d)
   712  
   713  	_, err := ctx.GetTxn(true)
   714  	c.Assert(err, IsNil)
   715  
   716  	testCreateTable(c, ctx, d, s.dbInfo, tblInfo)
   717  
   718  	t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   719  
   720  	// c2 is nil, which is not stored in kv.
   721  	row := types.MakeDatums(int64(1), nil, int(2))
   722  	handle, err := t.AddRecord(ctx, row)
   723  	c.Assert(err, IsNil)
   724  
   725  	err = ctx.FinishTxn(false)
   726  	c.Assert(err, IsNil)
   727  
   728  	checkOK := false
   729  
   730  	tc := &testDDLCallback{}
   731  	tc.onJobUpdated = func(job *model.Job) {
   732  		if checkOK {
   733  			return
   734  		}
   735  
   736  		t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   737  		// Add index on c2.
   738  		indexCol := getIndex(t, "c2")
   739  		if indexCol == nil {
   740  			return
   741  		}
   742  		s.checkAddOrDropIndex(c, indexCol.State, d, tblInfo, handle, indexCol, row, false)
   743  		if indexCol.State == model.StatePublic {
   744  			checkOK = true
   745  		}
   746  	}
   747  
   748  	d.hook = tc
   749  
   750  	// Use local ddl for callback test.
   751  	s.d.close()
   752  	d.close()
   753  	d.start()
   754  
   755  	job := testCreateIndex(c, ctx, d, s.dbInfo, tblInfo, true, "c2", "c2")
   756  	testCheckJobDone(c, d, job, true)
   757  
   758  	_, err = ctx.GetTxn(true)
   759  	c.Assert(err, IsNil)
   760  
   761  	job = testDropTable(c, ctx, d, s.dbInfo, tblInfo)
   762  	testCheckJobDone(c, d, job, false)
   763  
   764  	err = ctx.FinishTxn(false)
   765  	c.Assert(err, IsNil)
   766  
   767  	d.close()
   768  	s.d.start()
   769  }