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 }