944 lines
31 KiB
Go
944 lines
31 KiB
Go
// Copyright 2015 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package tidb
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
. "github.com/pingcap/check"
|
|
"github.com/pingcap/tidb/context"
|
|
"github.com/pingcap/tidb/domain"
|
|
"github.com/pingcap/tidb/kv"
|
|
"github.com/pingcap/tidb/model"
|
|
"github.com/pingcap/tidb/sessionctx"
|
|
"github.com/pingcap/tidb/store/localstore"
|
|
"github.com/pingcap/tidb/table/tables"
|
|
"github.com/pingcap/tidb/terror"
|
|
"github.com/pingcap/tidb/util/testleak"
|
|
"github.com/pingcap/tidb/util/types"
|
|
)
|
|
|
|
var (
|
|
_ = Suite(&testSessionSuite{})
|
|
_ = Suite(&test1435Suite{})
|
|
)
|
|
|
|
type testSessionSuite struct {
|
|
dbName string
|
|
createDBSQL string
|
|
dropDBSQL string
|
|
useDBSQL string
|
|
createTableSQL string
|
|
dropTableSQL string
|
|
selectSQL string
|
|
|
|
store kv.Storage
|
|
dom *domain.Domain
|
|
}
|
|
|
|
func (s *testSessionSuite) SetUpSuite(c *C) {
|
|
s.dbName = "test_session_db"
|
|
s.dropTableSQL = `Drop TABLE if exists t;`
|
|
s.createTableSQL = `CREATE TABLE t(id TEXT);`
|
|
s.selectSQL = `SELECT * from t;`
|
|
|
|
s.store = newStore(c, s.dbName)
|
|
dom, err := BootstrapSession(s.store)
|
|
c.Assert(err, IsNil)
|
|
s.dom = dom
|
|
}
|
|
|
|
func (s *testSessionSuite) TearDownSuite(c *C) {
|
|
removeStore(c, s.dbName)
|
|
s.dom.Close()
|
|
err := s.store.Close()
|
|
c.Assert(err, IsNil)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestSchemaCheckerSimple(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
lease := 5 * time.Millisecond
|
|
validator := domain.NewSchemaValidator(lease)
|
|
checker := &schemaLeaseChecker{SchemaValidator: validator}
|
|
|
|
// Add some schema versions and delta table IDs.
|
|
ts := uint64(time.Now().UnixNano())
|
|
validator.Update(ts, 0, 2, []int64{1})
|
|
validator.Update(ts, 2, 4, []int64{2})
|
|
|
|
// checker's schema version is the same as the current schema version.
|
|
checker.schemaVer = 4
|
|
err := checker.Check(ts)
|
|
c.Assert(err, IsNil)
|
|
|
|
// checker's schema version is less than the current schema version, and it doesn't exist in validator's items.
|
|
// checker's related table ID isn't in validator's changed table IDs.
|
|
checker.schemaVer = 2
|
|
checker.relatedTableIDs = []int64{3}
|
|
err = checker.Check(ts)
|
|
c.Assert(err, IsNil)
|
|
// The checker's schema version isn't in validator's items.
|
|
checker.schemaVer = 1
|
|
checker.relatedTableIDs = []int64{3}
|
|
err = checker.Check(ts)
|
|
c.Assert(terror.ErrorEqual(err, domain.ErrInfoSchemaChanged), IsTrue)
|
|
// checker's related table ID is in validator's changed table IDs.
|
|
checker.relatedTableIDs = []int64{2}
|
|
err = checker.Check(ts)
|
|
c.Assert(terror.ErrorEqual(err, domain.ErrInfoSchemaChanged), IsTrue)
|
|
|
|
// validator's latest schema version is expired.
|
|
time.Sleep(lease + time.Microsecond)
|
|
checker.schemaVer = 4
|
|
checker.relatedTableIDs = []int64{3}
|
|
err = checker.Check(ts)
|
|
c.Assert(err, IsNil)
|
|
nowTS := uint64(time.Now().UnixNano())
|
|
// Use checker.SchemaValidator.Check instead of checker.Check here because backoff make CI slow.
|
|
result := checker.SchemaValidator.Check(nowTS, checker.schemaVer, checker.relatedTableIDs)
|
|
c.Assert(result, Equals, domain.ResultUnknown)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIssue1118(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_issue1118"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
c.Assert(se.(*session).txn, IsNil)
|
|
|
|
// insert
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, "create table t (c1 int not null auto_increment, c2 int, PRIMARY KEY (c1))")
|
|
mustExecSQL(c, se, "insert into t set c2 = 11")
|
|
r := mustExecSQL(c, se, "select last_insert_id()")
|
|
row, err := r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1)
|
|
mustExecSQL(c, se, "insert into t (c2) values (22), (33), (44)")
|
|
r = mustExecSQL(c, se, "select last_insert_id()")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 2)
|
|
mustExecSQL(c, se, "insert into t (c1, c2) values (10, 55)")
|
|
r = mustExecSQL(c, se, "select last_insert_id()")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 2)
|
|
|
|
// replace
|
|
mustExecSQL(c, se, "replace t (c2) values(66)")
|
|
r = mustExecSQL(c, se, "select * from t")
|
|
rows, err := GetRows(r)
|
|
c.Assert(err, IsNil)
|
|
matches(c, rows, [][]interface{}{{1, 11}, {2, 22}, {3, 33}, {4, 44}, {10, 55}, {11, 66}})
|
|
r = mustExecSQL(c, se, "select last_insert_id()")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 11)
|
|
|
|
// update
|
|
mustExecSQL(c, se, "update t set c1=last_insert_id(c1 + 100)")
|
|
r = mustExecSQL(c, se, "select * from t")
|
|
rows, err = GetRows(r)
|
|
c.Assert(err, IsNil)
|
|
matches(c, rows, [][]interface{}{{101, 11}, {102, 22}, {103, 33}, {104, 44}, {110, 55}, {111, 66}})
|
|
r = mustExecSQL(c, se, "select last_insert_id()")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 111)
|
|
mustExecSQL(c, se, "insert into t (c2) values (77)")
|
|
r = mustExecSQL(c, se, "select last_insert_id()")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 112)
|
|
|
|
// drop
|
|
mustExecSQL(c, se, "drop table t")
|
|
r = mustExecSQL(c, se, "select last_insert_id()")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 112)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIssue827(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_issue827"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
se1 := newSession(c, s.store, dbName)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t1")
|
|
c.Assert(se.(*session).txn, IsNil)
|
|
mustExecSQL(c, se, "create table t1 (c2 int, c3 int, c1 int not null auto_increment, PRIMARY KEY (c1))")
|
|
mustExecSQL(c, se, "insert into t1 set c2 = 30")
|
|
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
c.Assert(se.(*session).txn, IsNil)
|
|
mustExecSQL(c, se, "create table t (c2 int, c1 int not null auto_increment, PRIMARY KEY (c1))")
|
|
mustExecSQL(c, se, "insert into t (c2) values (1), (2), (3), (4), (5)")
|
|
|
|
// insert values
|
|
lastInsertID := se.LastInsertID()
|
|
mustExecSQL(c, se, "begin")
|
|
mustExecSQL(c, se, "insert into t (c2) values (11), (12), (13)")
|
|
rs, err := exec(se, "select c1 from t where c2 = 11")
|
|
c.Assert(err, IsNil)
|
|
expect, err := GetRows(rs)
|
|
c.Assert(err, IsNil)
|
|
_, err = exec(se, "update t set c2 = 33 where c2 = 1")
|
|
c.Assert(err, IsNil)
|
|
|
|
mustExecSQL(c, se1, "begin")
|
|
mustExecSQL(c, se1, "update t set c2 = 22 where c2 = 1")
|
|
mustExecSQL(c, se1, "commit")
|
|
|
|
_, err = exec(se, "commit")
|
|
c.Assert(err, IsNil)
|
|
|
|
rs, err = exec(se, "select c1 from t where c2 = 11")
|
|
c.Assert(err, IsNil)
|
|
r, err := GetRows(rs)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(r, DeepEquals, expect)
|
|
currLastInsertID := se.GetSessionVars().PrevLastInsertID
|
|
c.Assert(lastInsertID+5, Equals, currLastInsertID)
|
|
|
|
// insert set
|
|
lastInsertID = currLastInsertID
|
|
mustExecSQL(c, se, "begin")
|
|
mustExecSQL(c, se, "insert into t set c2 = 31")
|
|
rs, err = exec(se, "select c1 from t where c2 = 31")
|
|
c.Assert(err, IsNil)
|
|
expect, err = GetRows(rs)
|
|
c.Assert(err, IsNil)
|
|
_, err = exec(se, "update t set c2 = 44 where c2 = 2")
|
|
c.Assert(err, IsNil)
|
|
|
|
mustExecSQL(c, se1, "begin")
|
|
mustExecSQL(c, se1, "update t set c2 = 55 where c2 = 2")
|
|
mustExecSQL(c, se1, "commit")
|
|
|
|
_, err = exec(se, "commit")
|
|
c.Assert(err, IsNil)
|
|
|
|
rs, err = exec(se, "select c1 from t where c2 = 31")
|
|
c.Assert(err, IsNil)
|
|
r, err = GetRows(rs)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(r, DeepEquals, expect)
|
|
currLastInsertID = se.GetSessionVars().PrevLastInsertID
|
|
c.Assert(lastInsertID+3, Equals, currLastInsertID)
|
|
|
|
// replace
|
|
lastInsertID = currLastInsertID
|
|
mustExecSQL(c, se, "begin")
|
|
mustExecSQL(c, se, "insert into t (c2) values (21), (22), (23)")
|
|
rs, err = exec(se, "select c1 from t where c2 = 21")
|
|
c.Assert(err, IsNil)
|
|
expect, err = GetRows(rs)
|
|
c.Assert(err, IsNil)
|
|
_, err = exec(se, "update t set c2 = 66 where c2 = 3")
|
|
c.Assert(err, IsNil)
|
|
|
|
mustExecSQL(c, se1, "begin")
|
|
mustExecSQL(c, se1, "update t set c2 = 77 where c2 = 3")
|
|
mustExecSQL(c, se1, "commit")
|
|
|
|
_, err = exec(se, "commit")
|
|
c.Assert(err, IsNil)
|
|
|
|
rs, err = exec(se, "select c1 from t where c2 = 21")
|
|
c.Assert(err, IsNil)
|
|
r, err = GetRows(rs)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(r, DeepEquals, expect)
|
|
currLastInsertID = se.GetSessionVars().PrevLastInsertID
|
|
c.Assert(lastInsertID+1, Equals, currLastInsertID)
|
|
|
|
// update
|
|
lastInsertID = currLastInsertID
|
|
mustExecSQL(c, se, "begin")
|
|
mustExecSQL(c, se, "insert into t set c2 = 41")
|
|
mustExecSQL(c, se, "update t set c1 = 0 where c2 = 41")
|
|
rs, err = exec(se, "select c1 from t where c2 = 41")
|
|
c.Assert(err, IsNil)
|
|
expect, err = GetRows(rs)
|
|
c.Assert(err, IsNil)
|
|
_, err = exec(se, "update t set c2 = 88 where c2 = 4")
|
|
c.Assert(err, IsNil)
|
|
|
|
mustExecSQL(c, se1, "begin")
|
|
mustExecSQL(c, se1, "update t set c2 = 99 where c2 = 4")
|
|
mustExecSQL(c, se1, "commit")
|
|
|
|
_, err = exec(se, "commit")
|
|
c.Assert(err, IsNil)
|
|
|
|
rs, err = exec(se, "select c1 from t where c2 = 41")
|
|
c.Assert(err, IsNil)
|
|
r, err = GetRows(rs)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(r, DeepEquals, expect)
|
|
currLastInsertID = se.GetSessionVars().PrevLastInsertID
|
|
c.Assert(lastInsertID+3, Equals, currLastInsertID)
|
|
|
|
// prepare
|
|
lastInsertID = currLastInsertID
|
|
mustExecSQL(c, se, "begin")
|
|
mustExecSQL(c, se, "prepare stmt from 'insert into t (c2) values (?)'")
|
|
mustExecSQL(c, se, "set @v1=100")
|
|
mustExecSQL(c, se, "set @v2=200")
|
|
mustExecSQL(c, se, "set @v3=300")
|
|
mustExecSQL(c, se, "execute stmt using @v1")
|
|
mustExecSQL(c, se, "execute stmt using @v2")
|
|
mustExecSQL(c, se, "execute stmt using @v3")
|
|
mustExecSQL(c, se, "deallocate prepare stmt")
|
|
rs, err = exec(se, "select c1 from t where c2 = 12")
|
|
c.Assert(err, IsNil)
|
|
expect, err = GetRows(rs)
|
|
c.Assert(err, IsNil)
|
|
_, err = exec(se, "update t set c2 = 111 where c2 = 5")
|
|
c.Assert(err, IsNil)
|
|
|
|
mustExecSQL(c, se1, "begin")
|
|
mustExecSQL(c, se1, "update t set c2 = 222 where c2 = 5")
|
|
mustExecSQL(c, se1, "commit")
|
|
|
|
_, err = exec(se, "commit")
|
|
c.Assert(err, IsNil)
|
|
|
|
rs, err = exec(se, "select c1 from t where c2 = 12")
|
|
c.Assert(err, IsNil)
|
|
r, err = GetRows(rs)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(r, DeepEquals, expect)
|
|
currLastInsertID = se.GetSessionVars().PrevLastInsertID
|
|
c.Assert(lastInsertID+3, Equals, currLastInsertID)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
se.Close()
|
|
se1.Close()
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIssue996(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_issue827"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
c.Assert(se.(*session).txn, IsNil)
|
|
mustExecSQL(c, se, "create table t (c2 int, c3 int, c1 int not null auto_increment, PRIMARY KEY (c1))")
|
|
mustExecSQL(c, se, "insert into t set c2 = 30")
|
|
|
|
// insert values
|
|
lastInsertID := se.LastInsertID()
|
|
mustExecSQL(c, se, "prepare stmt1 from 'insert into t (c2) values (?)'")
|
|
mustExecSQL(c, se, "set @v1=10")
|
|
mustExecSQL(c, se, "set @v2=20")
|
|
mustExecSQL(c, se, "execute stmt1 using @v1")
|
|
mustExecSQL(c, se, "execute stmt1 using @v2")
|
|
mustExecSQL(c, se, "deallocate prepare stmt1")
|
|
rs, err := exec(se, "select c1 from t where c2 = 20")
|
|
c.Assert(err, IsNil)
|
|
r, err := GetRows(rs)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(r, NotNil)
|
|
currLastInsertID := se.GetSessionVars().PrevLastInsertID
|
|
c.Assert(r[0][0].GetValue(), DeepEquals, int64(currLastInsertID))
|
|
c.Assert(lastInsertID+2, Equals, currLastInsertID)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIssue986(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
sqlText := `CREATE TABLE address (
|
|
id bigint(20) NOT NULL AUTO_INCREMENT,
|
|
PRIMARY KEY (id));`
|
|
dbName := "test_issue827"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
mustExecSQL(c, se, sqlText)
|
|
sqlText = `insert into address values ('10')`
|
|
mustExecSQL(c, se, sqlText)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIssue1089(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_issue1089"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
r := mustExecSQL(c, se, "select cast(0.5 as unsigned)")
|
|
row, err := r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1)
|
|
r = mustExecSQL(c, se, "select cast(-0.5 as signed)")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, -1)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIssue1135(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_issue1135"
|
|
dropDBSQL1 := fmt.Sprintf("drop database %s;", dbName)
|
|
dropDBSQL2 := fmt.Sprintf("drop database %s;", dbName+"1")
|
|
se := newSession(c, s.store, dbName)
|
|
se1 := newSession(c, s.store, dbName+"1")
|
|
|
|
mustExecSQL(c, se1, "drop table if exists t")
|
|
mustExecSQL(c, se1, "create table t (F1 VARCHAR(30));")
|
|
mustExecSQL(c, se1, "insert into t (F1) values ('1'), ('4');")
|
|
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, "create table t (F1 VARCHAR(30));")
|
|
mustExecSQL(c, se, "insert into t (F1) values ('1'), ('2');")
|
|
mustExecSQL(c, se, "delete m1 from t m2,t m1 where m1.F1>1;")
|
|
r := mustExecSQL(c, se, "select * from t;")
|
|
row, err := r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, []interface{}{'1'})
|
|
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, "create table t (F1 VARCHAR(30));")
|
|
mustExecSQL(c, se, "insert into t (F1) values ('1'), ('2');")
|
|
mustExecSQL(c, se, "delete m1 from t m1,t m2 where true and m1.F1<2;")
|
|
r = mustExecSQL(c, se, "select * from t;")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, []interface{}{'2'})
|
|
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, "create table t (F1 VARCHAR(30));")
|
|
mustExecSQL(c, se, "insert into t (F1) values ('1'), ('2');")
|
|
mustExecSQL(c, se, "delete m1 from t m1,t m2 where false;")
|
|
r = mustExecSQL(c, se, "select * from t;")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, []interface{}{'1'})
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, []interface{}{'2'})
|
|
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, "create table t (F1 VARCHAR(30));")
|
|
mustExecSQL(c, se, "insert into t (F1) values ('1'), ('2');")
|
|
mustExecSQL(c, se, "delete m1, m2 from t m1,t m2 where m1.F1>m2.F1;")
|
|
r = mustExecSQL(c, se, "select * from t;")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(row, IsNil)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, "create table t (F1 VARCHAR(30));")
|
|
mustExecSQL(c, se, "insert into t (F1) values ('1'), ('2');")
|
|
sql := fmt.Sprintf("delete %s.t from %s.t inner join %s.t where %s.t.F1 > %s.t.F1",
|
|
dbName+"1", dbName+"1", dbName, dbName+"1", dbName)
|
|
mustExecSQL(c, se1, sql)
|
|
r = mustExecSQL(c, se1, "select * from t;")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, []interface{}{'1'})
|
|
|
|
mustExecSQL(c, se, dropDBSQL1)
|
|
mustExecSQL(c, se, dropDBSQL2)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIssue1114(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_issue1114"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
mustExecSQL(c, se, "set @tmp = 0")
|
|
mustExecSQL(c, se, "set @tmp := @tmp + 1")
|
|
r := mustExecSQL(c, se, "select @tmp")
|
|
row, err := r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1)
|
|
|
|
r = mustExecSQL(c, se, "select @tmp1 = 1, @tmp2 := 2")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, nil, 2)
|
|
|
|
r = mustExecSQL(c, se, "select @tmp1 := 11, @tmp2")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 11, 2)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, "create table t (c int);")
|
|
mustExecSQL(c, se, "insert into t values (1),(2);")
|
|
mustExecSQL(c, se, "update t set c = 3 WHERE c = @var:= 1")
|
|
r = mustExecSQL(c, se, "select * from t")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 3)
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 2)
|
|
|
|
r = mustExecSQL(c, se, "select @tmp := count(*) from t")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 2)
|
|
|
|
r = mustExecSQL(c, se, "select @tmp := c-2 from t where c=3")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestMySQLTypes(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_mysql_types"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
r := mustExecSQL(c, se, `select 0x01 + 1, x'4D7953514C' = "MySQL"`)
|
|
row, err := r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 2, 1)
|
|
r.Close()
|
|
|
|
r = mustExecSQL(c, se, `select 0b01 + 1, 0b01000001 = "A"`)
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 2, 1)
|
|
r.Close()
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestHaving(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_having"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
mustExecFailed(c, se, "select c1 from t having c2")
|
|
mustExecFailed(c, se, "select c1 from t having c2 + 1")
|
|
mustExecFailed(c, se, "select c1 from t group by c2 + 1 having c2")
|
|
mustExecFailed(c, se, "select c1 from t group by c2 + 1 having c2 + 1")
|
|
mustExecFailed(c, se, "select c1 as c2, c2 from t having c2")
|
|
mustExecFailed(c, se, "select c1 as c2, c2 from t having c2 + 1")
|
|
mustExecFailed(c, se, "select c1 as a, c2 as a from t having a")
|
|
mustExecFailed(c, se, "select c1 as a, c2 as a from t having a + 1")
|
|
mustExecFailed(c, se, "select c1 + 1 from t having c1")
|
|
mustExecFailed(c, se, "select c1 + 1 from t having c1 + 1")
|
|
mustExecFailed(c, se, "select a.c1 as c, b.c1 as d from t as a, t as b having c1")
|
|
mustExecFailed(c, se, "select 1 from t having sum(avg(c1))")
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIssue461(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_issue461"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se1 := newSession(c, s.store, dbName)
|
|
mustExecSQL(c, se1,
|
|
`CREATE TABLE test ( id int(11) UNSIGNED NOT NULL AUTO_INCREMENT, val int UNIQUE, PRIMARY KEY (id)); `)
|
|
mustExecSQL(c, se1, "begin;")
|
|
mustExecSQL(c, se1, "insert into test(id, val) values(1, 1);")
|
|
se2 := newSession(c, s.store, dbName)
|
|
mustExecSQL(c, se2, "begin;")
|
|
mustExecSQL(c, se2, "insert into test(id, val) values(2, 2);")
|
|
se3 := newSession(c, s.store, dbName)
|
|
mustExecSQL(c, se3, "begin;")
|
|
mustExecSQL(c, se3, "insert into test(id, val) values(1, 2);")
|
|
mustExecSQL(c, se3, "commit;")
|
|
_, err := se1.Execute("commit")
|
|
c.Assert(err, NotNil)
|
|
// Check error type and error message
|
|
c.Assert(terror.ErrorEqual(err, kv.ErrKeyExists), IsTrue)
|
|
c.Assert(err.Error(), Equals, "[kv:1062]Duplicate entry '1' for key 'PRIMARY'")
|
|
|
|
_, err = se2.Execute("commit")
|
|
c.Assert(err, NotNil)
|
|
c.Assert(terror.ErrorEqual(err, kv.ErrKeyExists), IsTrue)
|
|
c.Assert(err.Error(), Equals, "[kv:1062]Duplicate entry '2' for key 'val'")
|
|
|
|
se := newSession(c, s.store, dbName)
|
|
mustExecSQL(c, se, "drop table test;")
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIssue463(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
// Testcase for https://github.com/pingcap/tidb/issues/463
|
|
dbName := "test_issue463"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
mustExecSQL(c, se, "DROP TABLE IF EXISTS test")
|
|
mustExecSQL(c, se,
|
|
`CREATE TABLE test (
|
|
id int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
val int UNIQUE,
|
|
PRIMARY KEY (id)
|
|
);`)
|
|
mustExecSQL(c, se, "insert into test(id, val) values(1, 1);")
|
|
mustExecFailed(c, se, "insert into test(id, val) values(2, 1);")
|
|
mustExecSQL(c, se, "insert into test(id, val) values(2, 2);")
|
|
|
|
mustExecSQL(c, se, "begin;")
|
|
mustExecSQL(c, se, "insert into test(id, val) values(3, 3);")
|
|
mustExecFailed(c, se, "insert into test(id, val) values(4, 3);")
|
|
mustExecSQL(c, se, "insert into test(id, val) values(4, 4);")
|
|
mustExecSQL(c, se, "commit;")
|
|
se1 := newSession(c, s.store, dbName)
|
|
mustExecSQL(c, se1, "begin;")
|
|
mustExecSQL(c, se1, "insert into test(id, val) values(5, 6);")
|
|
mustExecSQL(c, se, "begin;")
|
|
mustExecSQL(c, se, "insert into test(id, val) values(20, 6);")
|
|
mustExecSQL(c, se, "commit;")
|
|
mustExecFailed(c, se1, "commit;")
|
|
mustExecSQL(c, se1, "insert into test(id, val) values(5, 5);")
|
|
|
|
mustExecSQL(c, se, "drop table test;")
|
|
|
|
mustExecSQL(c, se,
|
|
`CREATE TABLE test (
|
|
id int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
val1 int UNIQUE,
|
|
val2 int UNIQUE,
|
|
PRIMARY KEY (id)
|
|
);`)
|
|
mustExecSQL(c, se, "insert into test(id, val1, val2) values(1, 1, 1);")
|
|
mustExecSQL(c, se, "insert into test(id, val1, val2) values(2, 2, 2);")
|
|
mustExecFailed(c, se, "update test set val1 = 3, val2 = 2 where id = 1;")
|
|
mustExecSQL(c, se, "insert into test(id, val1, val2) values(3, 3, 3);")
|
|
mustExecSQL(c, se, "drop table test;")
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIssue177(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_issue177"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
mustExecSQL(c, se, `drop table if exists t1;`)
|
|
mustExecSQL(c, se, `drop table if exists t2;`)
|
|
mustExecSQL(c, se, "CREATE TABLE `t1` ( `a` char(3) NOT NULL default '', `b` char(3) NOT NULL default '', `c` char(3) NOT NULL default '', PRIMARY KEY (`a`,`b`,`c`)) ENGINE=InnoDB;")
|
|
mustExecSQL(c, se, "CREATE TABLE `t2` ( `a` char(3) NOT NULL default '', `b` char(3) NOT NULL default '', `c` char(3) NOT NULL default '', PRIMARY KEY (`a`,`b`,`c`)) ENGINE=InnoDB;")
|
|
mustExecSQL(c, se, `INSERT INTO t1 VALUES (1,1,1);`)
|
|
mustExecSQL(c, se, `INSERT INTO t2 VALUES (1,1,1);`)
|
|
mustExecSQL(c, se, `PREPARE my_stmt FROM "SELECT t1.b, count(*) FROM t1 group by t1.b having count(*) > ALL (SELECT COUNT(*) FROM t2 WHERE t2.a=1 GROUP By t2.b)";`)
|
|
mustExecSQL(c, se, `EXECUTE my_stmt;`)
|
|
mustExecSQL(c, se, `EXECUTE my_stmt;`)
|
|
mustExecSQL(c, se, `deallocate prepare my_stmt;`)
|
|
mustExecSQL(c, se, `drop table t1,t2;`)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIssue454(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_issue454"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, "drop table if exists t1")
|
|
mustExecSQL(c, se, "create table t1 (c1 int, c2 int, c3 int);")
|
|
mustExecSQL(c, se, "insert into t1 set c1=1, c2=2, c3=1;")
|
|
mustExecSQL(c, se, "create table t (c1 int, c2 int, c3 int, primary key (c1));")
|
|
mustExecSQL(c, se, "insert into t set c1=1, c2=4;")
|
|
mustExecSQL(c, se, "insert into t select * from t1 limit 1 on duplicate key update c3=3333;")
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIssue456(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_issue456"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, "drop table if exists t1")
|
|
mustExecSQL(c, se, "create table t1 (c1 int, c2 int, c3 int);")
|
|
mustExecSQL(c, se, "replace into t1 set c1=1, c2=2, c3=1;")
|
|
mustExecSQL(c, se, "create table t (c1 int, c2 int, c3 int, primary key (c1));")
|
|
mustExecSQL(c, se, "replace into t set c1=1, c2=4;")
|
|
mustExecSQL(c, se, "replace into t select * from t1 limit 1;")
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
// TestIssue571 ...
|
|
// For https://github.com/pingcap/tidb/issues/571
|
|
func (s *testSessionSuite) TestIssue571(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_issue571"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
mustExecSQL(c, se, "begin")
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, "create table t (c int)")
|
|
mustExecSQL(c, se, "insert t values (1), (2), (3)")
|
|
mustExecSQL(c, se, "commit")
|
|
|
|
se1 := newSession(c, s.store, dbName)
|
|
se1.(*session).unlimitedRetryCount = true
|
|
mustExecSQL(c, se1, "SET SESSION autocommit=1;")
|
|
se2 := newSession(c, s.store, dbName)
|
|
se2.(*session).unlimitedRetryCount = true
|
|
mustExecSQL(c, se2, "SET SESSION autocommit=1;")
|
|
se3 := newSession(c, s.store, dbName)
|
|
se3.(*session).unlimitedRetryCount = true
|
|
mustExecSQL(c, se3, "SET SESSION autocommit=0;")
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(3)
|
|
f1 := func() {
|
|
defer wg.Done()
|
|
for i := 0; i < 30; i++ {
|
|
mustExecSQL(c, se1, "update t set c = 1;")
|
|
}
|
|
}
|
|
f2 := func() {
|
|
defer wg.Done()
|
|
for i := 0; i < 30; i++ {
|
|
mustExecSQL(c, se2, "update t set c = ?;", 1)
|
|
}
|
|
}
|
|
f3 := func() {
|
|
defer wg.Done()
|
|
for i := 0; i < 30; i++ {
|
|
mustExecSQL(c, se3, "begin")
|
|
mustExecSQL(c, se3, "update t set c = 1;")
|
|
mustExecSQL(c, se3, "commit")
|
|
}
|
|
}
|
|
go f1()
|
|
go f2()
|
|
go f3()
|
|
wg.Wait()
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIssue620(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_issue620"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t1")
|
|
mustExecSQL(c, se, "drop table if exists t2")
|
|
mustExecSQL(c, se, "drop table if exists t3")
|
|
mustExecSQL(c, se, "create table t1(id int primary key auto_increment, c int);")
|
|
mustExecSQL(c, se, "create table t2(c int);")
|
|
mustExecSQL(c, se, "insert into t2 values (1);")
|
|
mustExecSQL(c, se, "create table t3(id int, c int);")
|
|
mustExecSQL(c, se, "insert into t3 values (2,2);")
|
|
mustExecSQL(c, se, "insert into t1(c) select * from t2; insert into t1 select * from t3;")
|
|
mustExecMatch(c, se, "select * from t1;", [][]interface{}{{1, 1}, {2, 2}})
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIssue893(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_issue893"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
mustExecSQL(c, se, "drop table if exists t1; create table t1(id int ); insert into t1 values (1);")
|
|
mustExecMatch(c, se, "select * from t1;", [][]interface{}{{1}})
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIssue1265(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_issue1265"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t;")
|
|
mustExecSQL(c, se, "create table t (a decimal unique);")
|
|
mustExecSQL(c, se, "insert t values ('100');")
|
|
mustExecFailed(c, se, "insert t values ('1e2');")
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
type test1435Suite struct{}
|
|
|
|
func (s *test1435Suite) SetUpSuite(c *C) {
|
|
}
|
|
|
|
func (s *test1435Suite) TestIssue1435(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
localstore.MockRemoteStore = true
|
|
dbName := "test_issue1435"
|
|
store, dom := newStoreWithBootstrap(c, dbName)
|
|
defer dom.Close()
|
|
defer store.Close()
|
|
se := newSession(c, store, dbName)
|
|
se1 := newSession(c, store, dbName)
|
|
se2 := newSession(c, store, dbName)
|
|
// Make sure statements can't retry.
|
|
se.(*session).sessionVars.RetryInfo.Retrying = true
|
|
se1.(*session).sessionVars.RetryInfo.Retrying = true
|
|
se2.(*session).sessionVars.RetryInfo.Retrying = true
|
|
|
|
ctx := se.(context.Context)
|
|
mustExecSQL(c, se, "drop table if exists t;")
|
|
mustExecSQL(c, se, "create table t (a int);")
|
|
mustExecSQL(c, se, "drop table if exists t1;")
|
|
mustExecSQL(c, se, "create table t1 (a int);")
|
|
mustExecSQL(c, se, "drop table if exists t2;")
|
|
mustExecSQL(c, se, "create table t2 (a int);")
|
|
startCh1 := make(chan struct{}, 0)
|
|
startCh2 := make(chan struct{}, 0)
|
|
endCh1 := make(chan error, 0)
|
|
endCh2 := make(chan error, 0)
|
|
execFailedFunc := func(s Session, tbl string, start chan struct{}, end chan error) {
|
|
// execute successfully
|
|
_, err := exec(s, "begin;")
|
|
c.Check(err, IsNil)
|
|
<-start
|
|
<-start
|
|
|
|
_, err = exec(s, fmt.Sprintf("insert into %s values(1)", tbl))
|
|
c.Check(err, IsNil)
|
|
|
|
// table t1 executes failed
|
|
// table t2 executes successfully
|
|
_, err = exec(s, "commit")
|
|
end <- err
|
|
}
|
|
|
|
go execFailedFunc(se1, "t1", startCh1, endCh1)
|
|
go execFailedFunc(se2, "t2", startCh2, endCh2)
|
|
// Make sure two insert transactions are begin.
|
|
startCh1 <- struct{}{}
|
|
startCh2 <- struct{}{}
|
|
|
|
select {
|
|
case <-endCh1:
|
|
// Make sure the first insert statement isn't finish.
|
|
c.Error("The statement shouldn't be executed")
|
|
c.FailNow()
|
|
default:
|
|
}
|
|
// Make sure loading information schema is failed and server is invalid.
|
|
sessionctx.GetDomain(ctx).MockReloadFailed.SetValue(true)
|
|
err := sessionctx.GetDomain(ctx).Reload()
|
|
c.Assert(err, NotNil)
|
|
lease := sessionctx.GetDomain(ctx).DDL().GetLease()
|
|
time.Sleep(lease)
|
|
// Make sure insert to table t1 transaction executes.
|
|
startCh1 <- struct{}{}
|
|
// Make sure executing insert statement is failed when server is invalid.
|
|
mustExecFailed(c, se, "insert t values (100);")
|
|
err = <-endCh1
|
|
c.Assert(err, NotNil)
|
|
|
|
// recover
|
|
select {
|
|
case <-endCh2:
|
|
// Make sure the second insert statement isn't finish.
|
|
c.Error("The statement shouldn't be executed")
|
|
c.FailNow()
|
|
default:
|
|
}
|
|
|
|
ver, err := store.CurrentVersion()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(ver, NotNil)
|
|
sessionctx.GetDomain(ctx).MockReloadFailed.SetValue(false)
|
|
time.Sleep(lease)
|
|
mustExecSQL(c, se, "drop table if exists t;")
|
|
mustExecSQL(c, se, "create table t (a int);")
|
|
mustExecSQL(c, se, "insert t values (100);")
|
|
// Make sure insert to table t2 transaction executes.
|
|
startCh2 <- struct{}{}
|
|
err = <-endCh2
|
|
c.Assert(err, IsNil, Commentf("err:%v", err))
|
|
|
|
se.Close()
|
|
se1.Close()
|
|
se2.Close()
|
|
localstore.MockRemoteStore = false
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIndexColumnLength(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_index_column_length"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
mustExecSQL(c, se, "drop table if exists t;")
|
|
mustExecSQL(c, se, "create table t (c1 int, c2 blob);")
|
|
mustExecSQL(c, se, "create index idx_c1 on t(c1);")
|
|
mustExecSQL(c, se, "create index idx_c2 on t(c2(6));")
|
|
|
|
is := s.dom.InfoSchema()
|
|
tab, err2 := is.TableByName(model.NewCIStr(dbName), model.NewCIStr("t"))
|
|
c.Assert(err2, Equals, nil)
|
|
|
|
idxC1Cols := tables.FindIndexByColName(tab, "c1").Meta().Columns
|
|
c.Assert(idxC1Cols[0].Length, Equals, types.UnspecifiedLength)
|
|
|
|
idxC2Cols := tables.FindIndexByColName(tab, "c2").Meta().Columns
|
|
c.Assert(idxC2Cols[0].Length, Equals, 6)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIgnoreForeignKey(c *C) {
|
|
c.Skip("skip panic")
|
|
defer testleak.AfterTest(c)()
|
|
sqlText := `CREATE TABLE address (
|
|
id bigint(20) NOT NULL AUTO_INCREMENT,
|
|
user_id bigint(20) NOT NULL,
|
|
PRIMARY KEY (id),
|
|
CONSTRAINT FK_7rod8a71yep5vxasb0ms3osbg FOREIGN KEY (user_id) REFERENCES waimaiqa.user (id),
|
|
INDEX FK_7rod8a71yep5vxasb0ms3osbg (user_id) comment ''
|
|
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ROW_FORMAT=COMPACT COMMENT='' CHECKSUM=0 DELAY_KEY_WRITE=0;`
|
|
dbName := "test_ignore_foreignkey"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
mustExecSQL(c, se, sqlText)
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
// TestISColumns tests information_schema.columns.
|
|
func (s *testSessionSuite) TestISColumns(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_is_columns"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
sql := "select ORDINAL_POSITION from INFORMATION_SCHEMA.COLUMNS;"
|
|
mustExecSQL(c, se, sql)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|