github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/ddl/ddl_db_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_test
    15  
    16  import (
    17  	"database/sql"
    18  	"flag"
    19  	"fmt"
    20  	"io"
    21  	"math/rand"
    22  	"strings"
    23  	"time"
    24  
    25  	. "github.com/insionng/yougam/libraries/pingcap/check"
    26  	"github.com/insionng/yougam/libraries/pingcap/tidb"
    27  	_ "github.com/insionng/yougam/libraries/pingcap/tidb"
    28  	"github.com/insionng/yougam/libraries/pingcap/tidb/column"
    29  	"github.com/insionng/yougam/libraries/pingcap/tidb/context"
    30  	"github.com/insionng/yougam/libraries/pingcap/tidb/kv"
    31  	"github.com/insionng/yougam/libraries/pingcap/tidb/model"
    32  	"github.com/insionng/yougam/libraries/pingcap/tidb/sessionctx"
    33  	"github.com/insionng/yougam/libraries/pingcap/tidb/table"
    34  	"github.com/insionng/yougam/libraries/pingcap/tidb/terror"
    35  	"github.com/insionng/yougam/libraries/pingcap/tidb/util/testleak"
    36  	"github.com/insionng/yougam/libraries/pingcap/tidb/util/types"
    37  )
    38  
    39  func trySkipDBTest(c *C) {
    40  	// skip_ddl flag is defined in ddl package, we can't use it directly, so using flag Lookup to help us.
    41  	if f := flag.Lookup("skip_ddl"); f == nil || strings.ToLower(f.Value.String()) == "false" {
    42  		return
    43  	}
    44  
    45  	c.Skip("skip DB test")
    46  }
    47  
    48  var _ = Suite(&testDBSuite{})
    49  
    50  type testDBSuite struct {
    51  	db *sql.DB
    52  
    53  	store      kv.Storage
    54  	schemaName string
    55  
    56  	s     tidb.Session
    57  	lease time.Duration
    58  }
    59  
    60  func (s *testDBSuite) SetUpSuite(c *C) {
    61  	trySkipDBTest(c)
    62  
    63  	var err error
    64  
    65  	s.schemaName = "test_db"
    66  
    67  	uri := "memory://test"
    68  	s.store, err = tidb.NewStore(uri)
    69  	c.Assert(err, IsNil)
    70  
    71  	s.db, err = sql.Open("tidb", fmt.Sprintf("%s/%s", uri, s.schemaName))
    72  	c.Assert(err, IsNil)
    73  
    74  	s.s, err = tidb.CreateSession(s.store)
    75  	c.Assert(err, IsNil)
    76  
    77  	s.mustExec(c, "create table t1 (c1 int, c2 int, c3 int, primary key(c1))")
    78  	s.mustExec(c, "create table t2 (c1 int, c2 int, c3 int)")
    79  
    80  	// set proper schema lease
    81  	s.lease = 500 * time.Millisecond
    82  	ctx := s.s.(context.Context)
    83  	sessionctx.GetDomain(ctx).SetLease(s.lease)
    84  }
    85  
    86  func (s *testDBSuite) TearDownSuite(c *C) {
    87  	trySkipDBTest(c)
    88  
    89  	s.db.Close()
    90  
    91  	s.s.Close()
    92  }
    93  
    94  func (s *testDBSuite) TestIndex(c *C) {
    95  	defer testleak.AfterTest(c)()
    96  	s.testAddIndex(c)
    97  	s.testDropIndex(c)
    98  }
    99  
   100  func (s *testDBSuite) testGetTable(c *C, name string) table.Table {
   101  	ctx := s.s.(context.Context)
   102  	tbl, err := sessionctx.GetDomain(ctx).InfoSchema().TableByName(model.NewCIStr(s.schemaName), model.NewCIStr(name))
   103  	c.Assert(err, IsNil)
   104  	return tbl
   105  }
   106  
   107  func (s *testDBSuite) testAddIndex(c *C) {
   108  	done := make(chan struct{}, 1)
   109  
   110  	num := 100
   111  	// first add some rows
   112  	for i := 0; i < num; i++ {
   113  		s.mustExec(c, "insert into t1 values (?, ?, ?)", i, i, i)
   114  	}
   115  
   116  	go func() {
   117  		s.mustExec(c, "create index c3_index on t1 (c3)")
   118  		done <- struct{}{}
   119  	}()
   120  
   121  	deletedKeys := make(map[int]struct{})
   122  
   123  	ticker := time.NewTicker(s.lease / 2)
   124  	defer ticker.Stop()
   125  LOOP:
   126  	for {
   127  		select {
   128  		case <-done:
   129  			break LOOP
   130  		case <-ticker.C:
   131  			step := 10
   132  			// delete some rows, and add some data
   133  			for i := num; i < num+step; i++ {
   134  				n := rand.Intn(num)
   135  				deletedKeys[n] = struct{}{}
   136  				s.mustExec(c, "delete from t1 where c1 = ?", n)
   137  				s.mustExec(c, "insert into t1 values (?, ?, ?)", i, i, i)
   138  			}
   139  			num += step
   140  		}
   141  	}
   142  
   143  	// get exists keys
   144  	keys := make([]int, 0, num)
   145  	for i := 0; i < num; i++ {
   146  		if _, ok := deletedKeys[i]; ok {
   147  			continue
   148  		}
   149  		keys = append(keys, i)
   150  	}
   151  
   152  	// test index key
   153  	for _, key := range keys {
   154  		rows := s.mustQuery(c, "select c1 from t1 where c3 = ?", key)
   155  		matchRows(c, rows, [][]interface{}{{key}})
   156  	}
   157  
   158  	// test delete key not in index
   159  	for key := range deletedKeys {
   160  		rows := s.mustQuery(c, "select c1 from t1 where c3 = ?", key)
   161  		matchRows(c, rows, nil)
   162  	}
   163  
   164  	// test index range
   165  	for i := 0; i < 100; i++ {
   166  		index := rand.Intn(len(keys) - 3)
   167  		rows := s.mustQuery(c, "select c1 from t1 where c3 >= ? limit 3", keys[index])
   168  		matchRows(c, rows, [][]interface{}{{keys[index]}, {keys[index+1]}, {keys[index+2]}})
   169  	}
   170  
   171  	rows := s.mustQuery(c, "explain select c1 from t1 where c3 >= 100")
   172  
   173  	ay := dumpRows(c, rows)
   174  	c.Assert(strings.Contains(fmt.Sprintf("%v", ay), "c3_index"), IsTrue)
   175  
   176  	// get all row handles
   177  	ctx := s.s.(context.Context)
   178  	t := s.testGetTable(c, "t1")
   179  	handles := make(map[int64]struct{})
   180  	err := t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   181  		handles[h] = struct{}{}
   182  		return true, nil
   183  	})
   184  	c.Assert(err, IsNil)
   185  
   186  	// check in index
   187  	var nidx *column.IndexedCol
   188  	for _, tidx := range t.Indices() {
   189  		if tidx.Name.L == "c3_index" {
   190  			nidx = tidx
   191  			break
   192  		}
   193  	}
   194  	// Make sure there is index with name c3_index
   195  	c.Assert(nidx, NotNil)
   196  	c.Assert(nidx.ID, Greater, int64(0))
   197  	idx := kv.NewKVIndex(t.IndexPrefix(), "c3_index", nidx.ID, false)
   198  	txn, err := ctx.GetTxn(true)
   199  	c.Assert(err, IsNil)
   200  	defer ctx.FinishTxn(true)
   201  
   202  	it, err := idx.SeekFirst(txn)
   203  	c.Assert(err, IsNil)
   204  	defer it.Close()
   205  
   206  	for {
   207  		_, h, err := it.Next()
   208  		if terror.ErrorEqual(err, io.EOF) {
   209  			break
   210  		}
   211  
   212  		c.Assert(err, IsNil)
   213  		_, ok := handles[h]
   214  		c.Assert(ok, IsTrue)
   215  		delete(handles, h)
   216  	}
   217  
   218  	c.Assert(handles, HasLen, 0)
   219  }
   220  
   221  func (s *testDBSuite) testDropIndex(c *C) {
   222  	done := make(chan struct{}, 1)
   223  
   224  	s.mustExec(c, "delete from t1")
   225  
   226  	num := 100
   227  	//  add some rows
   228  	for i := 0; i < num; i++ {
   229  		s.mustExec(c, "insert into t1 values (?, ?, ?)", i, i, i)
   230  	}
   231  	t := s.testGetTable(c, "t1")
   232  	var c3idx *column.IndexedCol
   233  	for _, tidx := range t.Indices() {
   234  		if tidx.Name.L == "c3_index" {
   235  			c3idx = tidx
   236  			break
   237  		}
   238  	}
   239  	c.Assert(c3idx, NotNil)
   240  
   241  	go func() {
   242  		s.mustExec(c, "drop index c3_index on t1")
   243  		done <- struct{}{}
   244  	}()
   245  
   246  	ticker := time.NewTicker(s.lease / 2)
   247  	defer ticker.Stop()
   248  LOOP:
   249  	for {
   250  		select {
   251  		case <-done:
   252  			break LOOP
   253  		case <-ticker.C:
   254  			step := 10
   255  			// delete some rows, and add some data
   256  			for i := num; i < num+step; i++ {
   257  				n := rand.Intn(num)
   258  				s.mustExec(c, "update t1 set c2 = 1 where c1 = ?", n)
   259  				s.mustExec(c, "insert into t1 values (?, ?, ?)", i, i, i)
   260  			}
   261  			num += step
   262  		}
   263  	}
   264  
   265  	rows := s.mustQuery(c, "explain select c1 from t1 where c3 >= 0")
   266  
   267  	ay := dumpRows(c, rows)
   268  	c.Assert(strings.Contains(fmt.Sprintf("%v", ay), "c3_index"), IsFalse)
   269  
   270  	// check in index, must no index in kv
   271  	ctx := s.s.(context.Context)
   272  
   273  	handles := make(map[int64]struct{})
   274  
   275  	t = s.testGetTable(c, "t1")
   276  	var nidx *column.IndexedCol
   277  	for _, tidx := range t.Indices() {
   278  		if tidx.Name.L == "c3_index" {
   279  			nidx = tidx
   280  			break
   281  		}
   282  	}
   283  	// Make sure there is no index with name c3_index
   284  	c.Assert(nidx, IsNil)
   285  	idx := kv.NewKVIndex(t.IndexPrefix(), "c3_index", c3idx.ID, false)
   286  	txn, err := ctx.GetTxn(true)
   287  	c.Assert(err, IsNil)
   288  	defer ctx.FinishTxn(true)
   289  
   290  	it, err := idx.SeekFirst(txn)
   291  	c.Assert(err, IsNil)
   292  	defer it.Close()
   293  
   294  	for {
   295  		_, h, err := it.Next()
   296  		if terror.ErrorEqual(err, io.EOF) {
   297  			break
   298  		}
   299  
   300  		c.Assert(err, IsNil)
   301  		handles[h] = struct{}{}
   302  	}
   303  
   304  	c.Assert(handles, HasLen, 0)
   305  }
   306  
   307  func (s *testDBSuite) showColumns(c *C, tableName string) [][]interface{} {
   308  	rows := s.mustQuery(c, fmt.Sprintf("show columns from %s", tableName))
   309  	values := dumpRows(c, rows)
   310  	return values
   311  }
   312  
   313  func (s *testDBSuite) TestColumn(c *C) {
   314  	defer testleak.AfterTest(c)()
   315  	s.testAddColumn(c)
   316  	s.testDropColumn(c)
   317  }
   318  
   319  func (s *testDBSuite) testAddColumn(c *C) {
   320  	done := make(chan struct{}, 1)
   321  
   322  	num := 100
   323  	// add some rows
   324  	for i := 0; i < num; i++ {
   325  		s.mustExec(c, "insert into t2 values (?, ?, ?)", i, i, i)
   326  	}
   327  
   328  	go func() {
   329  		s.mustExec(c, "alter table t2 add column c4 int default -1")
   330  		done <- struct{}{}
   331  	}()
   332  
   333  	ticker := time.NewTicker(s.lease / 2)
   334  	defer ticker.Stop()
   335  	step := 10
   336  LOOP:
   337  	for {
   338  		select {
   339  		case <-done:
   340  			break LOOP
   341  		case <-ticker.C:
   342  			// delete some rows, and add some data
   343  			for i := num; i < num+step; i++ {
   344  				n := rand.Intn(num)
   345  				s.mustExec(c, "delete from t2 where c1 = ?", n)
   346  
   347  				_, err := s.db.Exec("insert into t2 values (?, ?, ?)", i, i, i)
   348  				if err != nil {
   349  					// if err is failed, the column number must be 4 now.
   350  					values := s.showColumns(c, "t2")
   351  					c.Assert(values, HasLen, 4)
   352  				}
   353  			}
   354  			num += step
   355  		}
   356  	}
   357  
   358  	// add data, here c4 must exist
   359  	for i := num; i < num+step; i++ {
   360  		s.mustExec(c, "insert into t2 values (?, ?, ?, ?)", i, i, i, i)
   361  	}
   362  
   363  	rows := s.mustQuery(c, "select count(c4) from t2")
   364  	values := dumpRows(c, rows)
   365  	c.Assert(values, HasLen, 1)
   366  	c.Assert(values[0], HasLen, 1)
   367  	count, ok := values[0][0].(int64)
   368  	c.Assert(ok, IsTrue)
   369  	c.Assert(count, Greater, int64(0))
   370  
   371  	rows = s.mustQuery(c, "select count(c4) from t2 where c4 = -1")
   372  	matchRows(c, rows, [][]interface{}{{count - int64(step)}})
   373  
   374  	for i := num; i < num+step; i++ {
   375  		rows := s.mustQuery(c, "select c4 from t2 where c4 = ?", i)
   376  		matchRows(c, rows, [][]interface{}{{i}})
   377  	}
   378  
   379  	ctx := s.s.(context.Context)
   380  	t := s.testGetTable(c, "t2")
   381  	i := 0
   382  	j := 0
   383  	defer ctx.FinishTxn(true)
   384  	err := t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   385  		i++
   386  		// c4 must be -1 or > 0
   387  		v, err1 := types.ToInt64(data[3].GetValue())
   388  		c.Assert(err1, IsNil)
   389  		if v == -1 {
   390  			j++
   391  		} else {
   392  			c.Assert(v, Greater, int64(0))
   393  		}
   394  		return true, nil
   395  	})
   396  	c.Assert(err, IsNil)
   397  	c.Assert(i, Equals, int(count))
   398  	c.Assert(i, LessEqual, num+step)
   399  	c.Assert(j, Equals, int(count)-step)
   400  }
   401  
   402  func (s *testDBSuite) testDropColumn(c *C) {
   403  	done := make(chan struct{}, 1)
   404  
   405  	s.mustExec(c, "delete from t2")
   406  
   407  	num := 100
   408  	// add some rows
   409  	for i := 0; i < num; i++ {
   410  		s.mustExec(c, "insert into t2 values (?, ?, ?, ?)", i, i, i, i)
   411  	}
   412  
   413  	// get c4 column id
   414  	ctx := s.s.(context.Context)
   415  	t := s.testGetTable(c, "t2")
   416  	col := t.Cols()[3]
   417  
   418  	go func() {
   419  		s.mustExec(c, "alter table t2 drop column c4")
   420  		done <- struct{}{}
   421  	}()
   422  
   423  	ticker := time.NewTicker(s.lease / 2)
   424  	defer ticker.Stop()
   425  	step := 10
   426  LOOP:
   427  	for {
   428  		select {
   429  		case <-done:
   430  			break LOOP
   431  		case <-ticker.C:
   432  			// delete some rows, and add some data
   433  			for i := num; i < num+step; i++ {
   434  				_, err := s.db.Exec("insert into t2 values (?, ?, ?)", i, i, i)
   435  				if err != nil {
   436  					// if err is failed, the column number must be 4 now.
   437  					values := s.showColumns(c, "t2")
   438  					c.Assert(values, HasLen, 4)
   439  				}
   440  			}
   441  			num += step
   442  		}
   443  	}
   444  
   445  	// add data, here c4 must not exist
   446  	for i := num; i < num+step; i++ {
   447  		s.mustExec(c, "insert into t2 values (?, ?, ?)", i, i, i)
   448  	}
   449  
   450  	rows := s.mustQuery(c, "select count(*) from t2")
   451  	values := dumpRows(c, rows)
   452  	c.Assert(values, HasLen, 1)
   453  	c.Assert(values[0], HasLen, 1)
   454  	count, ok := values[0][0].(int64)
   455  	c.Assert(ok, IsTrue)
   456  	c.Assert(count, Greater, int64(0))
   457  
   458  	txn, err := ctx.GetTxn(true)
   459  	c.Assert(err, IsNil)
   460  	defer ctx.FinishTxn(false)
   461  
   462  	i := 0
   463  	t = s.testGetTable(c, "t2")
   464  	// check c4 does not exist
   465  	err = t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []types.Datum, cols []*column.Col) (bool, error) {
   466  		i++
   467  		k := t.RecordKey(h, col)
   468  		_, err1 := txn.Get(k)
   469  		c.Assert(terror.ErrorEqual(err1, kv.ErrNotExist), IsTrue)
   470  		return true, nil
   471  	})
   472  	c.Assert(err, IsNil)
   473  	c.Assert(i, Equals, int(count))
   474  	c.Assert(i, LessEqual, num+step)
   475  }
   476  
   477  func (s *testDBSuite) mustExec(c *C, query string, args ...interface{}) sql.Result {
   478  	r, err := s.db.Exec(query, args...)
   479  	c.Assert(err, IsNil, Commentf("query %s, args %v", query, args))
   480  	return r
   481  }
   482  
   483  func (s *testDBSuite) mustQuery(c *C, query string, args ...interface{}) *sql.Rows {
   484  	r, err := s.db.Query(query, args...)
   485  	c.Assert(err, IsNil, Commentf("query %s, args %v", query, args))
   486  	return r
   487  }
   488  
   489  func dumpRows(c *C, rows *sql.Rows) [][]interface{} {
   490  	cols, err := rows.Columns()
   491  	c.Assert(err, IsNil)
   492  	ay := make([][]interface{}, 0)
   493  	for rows.Next() {
   494  		v := make([]interface{}, len(cols))
   495  		for i := range v {
   496  			v[i] = new(interface{})
   497  		}
   498  		err = rows.Scan(v...)
   499  		c.Assert(err, IsNil)
   500  
   501  		for i := range v {
   502  			v[i] = *(v[i].(*interface{}))
   503  		}
   504  		ay = append(ay, v)
   505  	}
   506  
   507  	rows.Close()
   508  	c.Assert(rows.Err(), IsNil, Commentf("%v", ay))
   509  	return ay
   510  }
   511  
   512  func matchRows(c *C, rows *sql.Rows, expected [][]interface{}) {
   513  	ay := dumpRows(c, rows)
   514  	c.Assert(len(ay), Equals, len(expected), Commentf("%v", expected))
   515  	for i := range ay {
   516  		match(c, ay[i], expected[i]...)
   517  	}
   518  }
   519  
   520  func match(c *C, row []interface{}, expected ...interface{}) {
   521  	c.Assert(len(row), Equals, len(expected))
   522  	for i := range row {
   523  		got := fmt.Sprintf("%v", row[i])
   524  		need := fmt.Sprintf("%v", expected[i])
   525  		c.Assert(got, Equals, need)
   526  	}
   527  }