2630 lines
91 KiB
Go
2630 lines
91 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"
|
|
"strings"
|
|
"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/mysql"
|
|
"github.com/pingcap/tidb/plan"
|
|
"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) TestPrepare(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_prepare"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
// create table
|
|
mustExecSQL(c, se, s.dropTableSQL)
|
|
mustExecSQL(c, se, s.createTableSQL)
|
|
// insert data
|
|
mustExecSQL(c, se, `INSERT INTO t VALUES ("id");`)
|
|
id, ps, fields, err := se.PrepareStmt("select id+? from t")
|
|
c.Assert(err, IsNil)
|
|
c.Assert(fields, HasLen, 1)
|
|
c.Assert(id, Equals, uint32(1))
|
|
c.Assert(ps, Equals, 1)
|
|
mustExecSQL(c, se, `set @a=1`)
|
|
_, err = se.ExecutePreparedStmt(id, "1")
|
|
c.Assert(err, IsNil)
|
|
err = se.DropPreparedStmt(id)
|
|
c.Assert(err, IsNil)
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
|
|
mustExecSQL(c, se, "prepare stmt from 'select 1+?'")
|
|
mustExecSQL(c, se, "set @v1=100")
|
|
rs := mustExecSQL(c, se, "execute stmt using @v1")
|
|
r, err := rs.Next()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(r.Data[0].GetFloat64(), Equals, float64(101))
|
|
|
|
mustExecSQL(c, se, "set @v2=200")
|
|
rs = mustExecSQL(c, se, "execute stmt using @v2")
|
|
r, err = rs.Next()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(r.Data[0].GetFloat64(), Equals, float64(201))
|
|
|
|
mustExecSQL(c, se, "set @v3=300")
|
|
rs = mustExecSQL(c, se, "execute stmt using @v3")
|
|
r, err = rs.Next()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(r.Data[0].GetFloat64(), Equals, float64(301))
|
|
mustExecSQL(c, se, "deallocate prepare stmt")
|
|
}
|
|
|
|
func (s *testSessionSuite) TestAffectedRows(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_affect_rows"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
mustExecSQL(c, se, s.dropTableSQL)
|
|
mustExecSQL(c, se, s.createTableSQL)
|
|
mustExecSQL(c, se, `INSERT INTO t VALUES ("a");`)
|
|
c.Assert(int(se.AffectedRows()), Equals, 1)
|
|
mustExecSQL(c, se, `INSERT INTO t VALUES ("b");`)
|
|
c.Assert(int(se.AffectedRows()), Equals, 1)
|
|
mustExecSQL(c, se, `UPDATE t set id = 'c' where id = 'a';`)
|
|
c.Assert(int(se.AffectedRows()), Equals, 1)
|
|
mustExecSQL(c, se, `UPDATE t set id = 'a' where id = 'a';`)
|
|
c.Assert(int(se.AffectedRows()), Equals, 0)
|
|
mustExecSQL(c, se, `SELECT * from t;`)
|
|
c.Assert(int(se.AffectedRows()), Equals, 0)
|
|
|
|
mustExecSQL(c, se, s.dropTableSQL)
|
|
mustExecSQL(c, se, "create table t (id int, data int)")
|
|
mustExecSQL(c, se, `INSERT INTO t VALUES (1, 0), (0, 0), (1, 1);`)
|
|
mustExecSQL(c, se, `UPDATE t set id = 1 where data = 0;`)
|
|
c.Assert(int(se.AffectedRows()), Equals, 1)
|
|
|
|
mustExecSQL(c, se, s.dropTableSQL)
|
|
mustExecSQL(c, se, "create table t (id int, c1 timestamp);")
|
|
mustExecSQL(c, se, `insert t values(1, 0);`)
|
|
mustExecSQL(c, se, `UPDATE t set id = 1 where id = 1;`)
|
|
c.Assert(int(se.AffectedRows()), Equals, 0)
|
|
|
|
// With ON DUPLICATE KEY UPDATE, the affected-rows value per row is 1 if the row is inserted as a new row,
|
|
// 2 if an existing row is updated, and 0 if an existing row is set to its current values.
|
|
mustExecSQL(c, se, s.dropTableSQL)
|
|
mustExecSQL(c, se, "create table t (c1 int PRIMARY KEY, c2 int);")
|
|
mustExecSQL(c, se, `insert t values(1, 1);`)
|
|
mustExecSQL(c, se, `insert into t values (1, 1) on duplicate key update c2=2;`)
|
|
c.Assert(int(se.AffectedRows()), Equals, 2)
|
|
mustExecSQL(c, se, `insert into t values (1, 1) on duplicate key update c2=2;`)
|
|
c.Assert(int(se.AffectedRows()), Equals, 0)
|
|
createSQL := `CREATE TABLE IF NOT EXISTS test (
|
|
id VARCHAR(36) PRIMARY KEY NOT NULL,
|
|
factor INTEGER NOT NULL DEFAULT 2);`
|
|
mustExecSQL(c, se, createSQL)
|
|
insertSQL := `INSERT INTO test(id) VALUES('id') ON DUPLICATE KEY UPDATE factor=factor+3;`
|
|
mustExecSQL(c, se, insertSQL)
|
|
c.Assert(int(se.AffectedRows()), Equals, 1)
|
|
mustExecSQL(c, se, insertSQL)
|
|
c.Assert(int(se.AffectedRows()), Equals, 2)
|
|
mustExecSQL(c, se, insertSQL)
|
|
c.Assert(int(se.AffectedRows()), Equals, 2)
|
|
|
|
se.SetClientCapability(mysql.ClientFoundRows)
|
|
mustExecSQL(c, se, s.dropTableSQL)
|
|
mustExecSQL(c, se, "create table t (id int, data int)")
|
|
mustExecSQL(c, se, `INSERT INTO t VALUES (1, 0), (0, 0), (1, 1);`)
|
|
mustExecSQL(c, se, `UPDATE t set id = 1 where data = 0;`)
|
|
c.Assert(int(se.AffectedRows()), Equals, 2)
|
|
|
|
sessionExec(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestString(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
se := newSession(c, s.store, s.dbName)
|
|
sessionExec(c, se, "select 1")
|
|
// here to check the panic bug in String() when txn is nil after committed.
|
|
c.Log(se.String())
|
|
}
|
|
|
|
func (s *testSessionSuite) TestResultField(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_result_field"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
// create table
|
|
mustExecSQL(c, se, s.dropTableSQL)
|
|
mustExecSQL(c, se, "create table t (id int);")
|
|
|
|
mustExecSQL(c, se, `INSERT INTO t VALUES (1);`)
|
|
mustExecSQL(c, se, `INSERT INTO t VALUES (2);`)
|
|
r := mustExecSQL(c, se, `SELECT count(*) from t;`)
|
|
c.Assert(r, NotNil)
|
|
_, err := GetRows(r)
|
|
c.Assert(err, IsNil)
|
|
fields, err := r.Fields()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(len(fields), Equals, 1)
|
|
field := fields[0].Column
|
|
c.Assert(field.Tp, Equals, mysql.TypeLonglong)
|
|
c.Assert(field.Flen, Equals, 21)
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestPrimaryKeyAutoincrement(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_primary_key_auto_increment"
|
|
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 (id BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL, name varchar(255) UNIQUE NOT NULL, status int)")
|
|
mustExecSQL(c, se, "insert t (name) values (?)", "abc")
|
|
id := se.LastInsertID()
|
|
c.Check(id != 0, IsTrue)
|
|
|
|
se2 := newSession(c, s.store, dbName)
|
|
rs := mustExecSQL(c, se2, "select * from t")
|
|
c.Assert(rs, NotNil)
|
|
row, err := rs.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, id, []byte("abc"), nil)
|
|
|
|
mustExecSQL(c, se, "update t set name = 'abc', status = 1 where id = ?", id)
|
|
rs = mustExecSQL(c, se2, "select * from t")
|
|
c.Assert(rs, NotNil)
|
|
row, err = rs.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, id, []byte("abc"), 1)
|
|
// Check for pass bool param to tidb prepared statement
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, "create table t (id tiny)")
|
|
mustExecSQL(c, se, "insert t values (?)", true)
|
|
rs = mustExecSQL(c, se, "select * from t")
|
|
c.Assert(rs, NotNil)
|
|
row, err = rs.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, int8(1))
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestAutoIncrementID(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_auto_increment_id"
|
|
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 (id BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL)")
|
|
mustExecSQL(c, se, "insert t values ()")
|
|
mustExecSQL(c, se, "insert t values ()")
|
|
mustExecSQL(c, se, "insert t values ()")
|
|
se.Execute("drop table if exists t;")
|
|
mustExecSQL(c, se, "create table t (id BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL)")
|
|
mustExecSQL(c, se, "insert t values ()")
|
|
lastID := se.LastInsertID()
|
|
c.Assert(lastID, Less, uint64(4))
|
|
mustExecSQL(c, se, "insert t () values ()")
|
|
c.Assert(se.LastInsertID(), Greater, lastID)
|
|
mustExecSQL(c, se, "insert t () select 100")
|
|
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, "create table t (i tinyint unsigned not null auto_increment, primary key (i));")
|
|
mustExecSQL(c, se, "insert into t set i = 254;")
|
|
mustExecSQL(c, se, "insert t values ()")
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func checkTxn(c *C, se Session, stmt string, expectStatus uint16) {
|
|
mustExecSQL(c, se, stmt)
|
|
if expectStatus != 0 {
|
|
c.Assert(se.(*session).txn.Valid(), IsTrue)
|
|
}
|
|
}
|
|
|
|
func checkAutocommit(c *C, se Session, expectStatus uint16) {
|
|
ret := se.(*session).sessionVars.Status & mysql.ServerStatusAutocommit
|
|
c.Assert(ret, Equals, expectStatus)
|
|
}
|
|
|
|
// See https://dev.mysql.com/doc/internals/en/status-flags.html
|
|
func (s *testSessionSuite) TestAutocommit(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_auto_commit"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
checkTxn(c, se, "drop table if exists t;", 0)
|
|
checkAutocommit(c, se, 2)
|
|
checkTxn(c, se, "create table t (id BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL)", 0)
|
|
checkAutocommit(c, se, 2)
|
|
checkTxn(c, se, "insert t values ()", 0)
|
|
checkAutocommit(c, se, 2)
|
|
checkTxn(c, se, "begin", 1)
|
|
checkAutocommit(c, se, 2)
|
|
checkTxn(c, se, "insert t values ()", 1)
|
|
checkAutocommit(c, se, 2)
|
|
checkTxn(c, se, "drop table if exists t;", 0)
|
|
checkAutocommit(c, se, 2)
|
|
|
|
checkTxn(c, se, "create table t (id BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL)", 0)
|
|
checkAutocommit(c, se, 2)
|
|
checkTxn(c, se, "set autocommit=0;", 0)
|
|
checkAutocommit(c, se, 0)
|
|
checkTxn(c, se, "insert t values ()", 1)
|
|
checkAutocommit(c, se, 0)
|
|
checkTxn(c, se, "commit", 0)
|
|
checkAutocommit(c, se, 0)
|
|
checkTxn(c, se, "drop table if exists t;", 0)
|
|
checkAutocommit(c, se, 0)
|
|
checkTxn(c, se, "set autocommit='On';", 0)
|
|
checkAutocommit(c, se, 2)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func checkInTrans(c *C, se Session, stmt string, expectStatus uint16) {
|
|
checkTxn(c, se, stmt, expectStatus)
|
|
ret := se.(*session).sessionVars.Status & mysql.ServerStatusInTrans
|
|
c.Assert(ret, Equals, expectStatus)
|
|
}
|
|
|
|
// See https://dev.mysql.com/doc/internals/en/status-flags.html
|
|
func (s *testSessionSuite) TestInTrans(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_intrans"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
checkInTrans(c, se, "drop table if exists t;", 0)
|
|
checkInTrans(c, se, "create table t (id BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL)", 0)
|
|
checkInTrans(c, se, "insert t values ()", 0)
|
|
checkInTrans(c, se, "begin", 1)
|
|
checkInTrans(c, se, "insert t values ()", 1)
|
|
checkInTrans(c, se, "drop table if exists t;", 0)
|
|
checkInTrans(c, se, "create table t (id BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL)", 0)
|
|
checkInTrans(c, se, "insert t values ()", 0)
|
|
checkInTrans(c, se, "commit", 0)
|
|
checkInTrans(c, se, "insert t values ()", 0)
|
|
|
|
checkInTrans(c, se, "set autocommit=0;", 0)
|
|
checkInTrans(c, se, "begin", 1)
|
|
checkInTrans(c, se, "insert t values ()", 1)
|
|
checkInTrans(c, se, "commit", 0)
|
|
checkInTrans(c, se, "insert t values ()", 1)
|
|
checkInTrans(c, se, "commit", 0)
|
|
|
|
checkInTrans(c, se, "set autocommit=1;", 0)
|
|
checkInTrans(c, se, "drop table if exists t;", 0)
|
|
checkInTrans(c, se, "create table t (id BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL)", 0)
|
|
checkInTrans(c, se, "begin", 1)
|
|
checkInTrans(c, se, "insert t values ()", 1)
|
|
checkInTrans(c, se, "rollback", 0)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
// See http://dev.mysql.com/doc/refman/5.7/en/commit.html
|
|
func (s *testSessionSuite) testRowLock(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_row_lock"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
se1 := newSession(c, s.store, dbName)
|
|
se2 := 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 (c1 int, c2 int, c3 int)")
|
|
mustExecSQL(c, se, "insert t values (11, 2, 3)")
|
|
mustExecSQL(c, se, "insert t values (12, 2, 3)")
|
|
mustExecSQL(c, se, "insert t values (13, 2, 3)")
|
|
|
|
mustExecSQL(c, se1, "begin")
|
|
mustExecSQL(c, se1, "update t set c2=21 where c1=11")
|
|
|
|
mustExecSQL(c, se2, "begin")
|
|
mustExecSQL(c, se2, "update t set c2=211 where c1=11")
|
|
mustExecSQL(c, se2, "commit")
|
|
|
|
_, err := exec(se1, "commit")
|
|
// se1 will retry and the final value is 21
|
|
c.Assert(err, IsNil)
|
|
// Check the result is correct
|
|
se3 := newSession(c, s.store, dbName)
|
|
r := mustExecSQL(c, se3, "select c2 from t where c1=11")
|
|
rows, err := GetRows(r)
|
|
matches(c, rows, [][]interface{}{{21}})
|
|
|
|
mustExecSQL(c, se1, "begin")
|
|
mustExecSQL(c, se1, "update t set c2=21 where c1=11")
|
|
|
|
mustExecSQL(c, se2, "begin")
|
|
mustExecSQL(c, se2, "update t set c2=22 where c1=12")
|
|
mustExecSQL(c, se2, "commit")
|
|
|
|
mustExecSQL(c, se1, "commit")
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
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.LastInsertID()
|
|
c.Assert(lastInsertID+5, Equals, currLastInsertID)
|
|
|
|
// insert set
|
|
lastInsertID = se.LastInsertID()
|
|
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.LastInsertID()
|
|
c.Assert(lastInsertID+3, Equals, currLastInsertID)
|
|
|
|
// replace
|
|
lastInsertID = se.LastInsertID()
|
|
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.LastInsertID()
|
|
c.Assert(lastInsertID+1, Equals, currLastInsertID)
|
|
|
|
// update
|
|
lastInsertID = se.LastInsertID()
|
|
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.LastInsertID()
|
|
c.Assert(lastInsertID+3, Equals, currLastInsertID)
|
|
|
|
// prepare
|
|
lastInsertID = se.LastInsertID()
|
|
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.LastInsertID()
|
|
c.Assert(lastInsertID+3, Equals, currLastInsertID)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
err = se.Close()
|
|
c.Assert(err, IsNil)
|
|
err = se1.Close()
|
|
c.Assert(err, IsNil)
|
|
}
|
|
|
|
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.LastInsertID()
|
|
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) TestSelectForUpdate(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_select_for_update"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
se1 := newSession(c, s.store, dbName)
|
|
se2 := 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 (c1 int, c2 int, c3 int)")
|
|
mustExecSQL(c, se, "insert t values (11, 2, 3)")
|
|
mustExecSQL(c, se, "insert t values (12, 2, 3)")
|
|
mustExecSQL(c, se, "insert t values (13, 2, 3)")
|
|
|
|
mustExecSQL(c, se, "create table t1 (c1 int)")
|
|
mustExecSQL(c, se, "insert t1 values (11)")
|
|
|
|
// conflict
|
|
mustExecSQL(c, se1, "begin")
|
|
rs, err := exec(se1, "select * from t where c1=11 for update")
|
|
c.Assert(err, IsNil)
|
|
_, err = GetRows(rs)
|
|
|
|
mustExecSQL(c, se2, "begin")
|
|
mustExecSQL(c, se2, "update t set c2=211 where c1=11")
|
|
mustExecSQL(c, se2, "commit")
|
|
|
|
_, err = exec(se1, "commit")
|
|
c.Assert(err, NotNil)
|
|
err = se1.(*session).retry(10)
|
|
// retry should fail
|
|
c.Assert(err, NotNil)
|
|
|
|
// no conflict for subquery.
|
|
mustExecSQL(c, se1, "begin")
|
|
rs, err = exec(se1, "select * from t where exists(select null from t1 where t1.c1=t.c1) for update")
|
|
c.Assert(err, IsNil)
|
|
_, err = GetRows(rs)
|
|
|
|
mustExecSQL(c, se2, "begin")
|
|
mustExecSQL(c, se2, "update t set c2=211 where c1=12")
|
|
mustExecSQL(c, se2, "commit")
|
|
|
|
_, err = exec(se1, "commit")
|
|
c.Assert(err, IsNil)
|
|
|
|
// not conflict
|
|
mustExecSQL(c, se1, "begin")
|
|
rs, err = exec(se1, "select * from t where c1=11 for update")
|
|
_, err = GetRows(rs)
|
|
|
|
mustExecSQL(c, se2, "begin")
|
|
mustExecSQL(c, se2, "update t set c2=22 where c1=12")
|
|
mustExecSQL(c, se2, "commit")
|
|
|
|
mustExecSQL(c, se1, "commit")
|
|
|
|
// not conflict, auto commit
|
|
mustExecSQL(c, se1, "set @@autocommit=1;")
|
|
rs, err = exec(se1, "select * from t where c1=11 for update")
|
|
_, err = GetRows(rs)
|
|
|
|
mustExecSQL(c, se2, "begin")
|
|
mustExecSQL(c, se2, "update t set c2=211 where c1=11")
|
|
mustExecSQL(c, se2, "commit")
|
|
|
|
_, err = exec(se1, "commit")
|
|
c.Assert(err, IsNil)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
err = se.Close()
|
|
c.Assert(err, IsNil)
|
|
err = se1.Close()
|
|
c.Assert(err, IsNil)
|
|
err = se2.Close()
|
|
c.Assert(err, IsNil)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestRow(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_row"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
r := mustExecSQL(c, se, "select row(1, 1) in (row(1, 1))")
|
|
row, err := r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1)
|
|
|
|
r = mustExecSQL(c, se, "select row(1, 1) in (row(1, 0))")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 0)
|
|
|
|
r = mustExecSQL(c, se, "select row(1, 1) in (select 1, 1)")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1)
|
|
|
|
r = mustExecSQL(c, se, "select row(1, 1) > row(1, 0)")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1)
|
|
|
|
r = mustExecSQL(c, se, "select row(1, 1) > (select 1, 0)")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1)
|
|
|
|
r = mustExecSQL(c, se, "select 1 > (select 1)")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 0)
|
|
|
|
r = mustExecSQL(c, se, "select (select 1)")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIndex(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_index"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
mustExecSQL(c, se, "create table if not exists test_index (c1 int, c double, index(c1), index(c))")
|
|
mustExecSQL(c, se, "insert into test_index values (1, 2), (3, null)")
|
|
r := mustExecSQL(c, se, "select c1 from test_index where c > 0")
|
|
rows, err := GetRows(r)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(rows, HasLen, 1)
|
|
match(c, rows[0], 1)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t1, t2")
|
|
mustExecSQL(c, se, `
|
|
create table t1 (c1 int, primary key(c1));
|
|
create table t2 (c2 int, primary key(c2));`)
|
|
mustExecSQL(c, se, `
|
|
insert into t1 values (1), (2);
|
|
insert into t2 values (2);`)
|
|
|
|
r = mustExecSQL(c, se, "select * from t1 left join t2 on t1.c1 = t2.c2 order by t1.c1")
|
|
rows, err = GetRows(r)
|
|
c.Assert(err, IsNil)
|
|
matches(c, rows, [][]interface{}{{1, nil}, {2, 2}})
|
|
|
|
r = mustExecSQL(c, se, "select * from t1 left join t2 on t1.c1 = t2.c2 where t2.c2 < 10")
|
|
rows, err = GetRows(r)
|
|
c.Assert(err, IsNil)
|
|
matches(c, rows, [][]interface{}{{2, 2}})
|
|
|
|
mustExecSQL(c, se, "create table if not exists test_varchar_index (c1 varchar(255), index(c1))")
|
|
mustExecSQL(c, se, "insert test_varchar_index values (''), ('a')")
|
|
mustExecMatch(c, se, "select * from test_varchar_index where c1 like ''", [][]interface{}{{[]byte("")}})
|
|
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, "create table t (c1 int, c2 int)")
|
|
mustExecSQL(c, se, "insert into t values (1,2), (1,2)")
|
|
mustExecSQL(c, se, "create index idx_0 on t(c1)")
|
|
mustExecSQL(c, se, "create index idx_1 on t(c2)")
|
|
r = mustExecSQL(c, se, "select c1 as c2 from t where c1 >= 2")
|
|
rows, err = GetRows(r)
|
|
c.Assert(err, IsNil)
|
|
matches(c, rows, [][]interface{}{})
|
|
|
|
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) TestExpression(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_expression"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
r := mustExecSQL(c, se, `select + (1 > 0), -(1 >0), + (1 < 0), - (1 < 0)`)
|
|
row, err := r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1, -1, 0, 0)
|
|
r.Close()
|
|
|
|
r = mustExecSQL(c, se, "select 1 <=> 1, 1 <=> null, null <=> null, null <=> (select null)")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1, 0, 1, 1)
|
|
r.Close()
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestSelect(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_select"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
mustExecSQL(c, se, "create table if not exists t (c1 int, c2 int)")
|
|
mustExecSQL(c, se, "create table if not exists t1 (c1 int, c2 int)")
|
|
|
|
_, err := se.Execute("select * from t as a join t as a")
|
|
c.Assert(err, NotNil)
|
|
|
|
_, err = se.Execute("select * from t join t1 as t")
|
|
c.Assert(err, NotNil)
|
|
|
|
_, err = se.Execute("select * from t join test.t")
|
|
c.Assert(err, NotNil)
|
|
|
|
_, err = se.Execute("select * from t as a join (select 1) as a")
|
|
c.Assert(err, IsNil)
|
|
|
|
r := mustExecSQL(c, se, "select 1, 2 from dual")
|
|
row, err := r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1, 2)
|
|
|
|
// Testcase For https://github.com/pingcap/tidb/issues/1071
|
|
r = mustExecSQL(c, se, `select 1 from dual where "0.1"`)
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(row, IsNil)
|
|
r = mustExecSQL(c, se, "select 1 from dual where 0.8")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1)
|
|
r = mustExecSQL(c, se, "select 1, count(*) from dual where 0.1")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1, 0)
|
|
r = mustExecSQL(c, se, "select count(*), 1 from dual where 0.8")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1, 1)
|
|
r = mustExecSQL(c, se, "select 1, 2 from dual where 0.1")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(row, IsNil)
|
|
mustExecSQL(c, se, "create table if not exists t2 (c1 int, c2 int)")
|
|
mustExecSQL(c, se, "insert into t2 (c1, c2) values(1, 1), (2, 2), (3, 3)")
|
|
r = mustExecSQL(c, se, "select 1 from t2 where 0.1")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(row, IsNil)
|
|
r = mustExecSQL(c, se, "select 1 from t2 where 0.9")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1)
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1)
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1)
|
|
r = mustExecSQL(c, se, "select sum(c1) from t2 where 0.1")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, nil)
|
|
r = mustExecSQL(c, se, "select sum(c1), c2 from t2 where 0.1")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, nil, nil)
|
|
r = mustExecSQL(c, se, "select 1+2, count(c1) from t2 where 0.1")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 3, 0)
|
|
|
|
r = mustExecSQL(c, se, "select 1, 2 from dual where not exists (select * from t where c1=2)")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1, 2)
|
|
|
|
r = mustExecSQL(c, se, "select 1, 2")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1, 2)
|
|
|
|
r = mustExecSQL(c, se, `select '''a''', """a""", 'pingcap ''-->'' tidb'`)
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, `'a'`, `"a"`, `pingcap '-->' tidb`)
|
|
|
|
r = mustExecSQL(c, se, `select '\'a\'', "\"a\"";`)
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, `'a'`, `"a"`)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, "create table t (c varchar(20))")
|
|
mustExecSQL(c, se, `insert t values("pingcap '-->' tidb")`)
|
|
|
|
r = mustExecSQL(c, se, `select * from t where c like 'pingcap ''-->'' tidb'`)
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, []byte(`pingcap '-->' tidb`))
|
|
|
|
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 (c1 int, c11 int)")
|
|
mustExecSQL(c, se, "create table t2 (c2 int)")
|
|
mustExecSQL(c, se, "create table t3 (c3 int)")
|
|
mustExecSQL(c, se, "insert into t1 values (1, 1), (2, 2), (3, 3)")
|
|
mustExecSQL(c, se, "insert into t2 values (1), (1), (2)")
|
|
mustExecSQL(c, se, "insert into t3 values (1), (3)")
|
|
|
|
r = mustExecSQL(c, se, "select * from t1 left join t2 on t1.c1 = t2.c2 left join t3 on t1.c1 = t3.c3 order by t1.c1, t2.c2, t3.c3")
|
|
rows, err := GetRows(r)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(rows, HasLen, 4)
|
|
match(c, rows[0], 1, 1, 1, 1)
|
|
match(c, rows[1], 1, 1, 1, 1)
|
|
match(c, rows[2], 2, 2, 2, nil)
|
|
match(c, rows[3], 3, 3, nil, 3)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, "create table t (c float(8))")
|
|
mustExecSQL(c, se, "insert into t values (3.12)")
|
|
r = mustExecSQL(c, se, "select * from t")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 3.12)
|
|
|
|
mustExecSQL(c, se, `drop table if exists t;create table t (c int);insert into t values (1);`)
|
|
r = mustExecSQL(c, se, "select a.c from t as a where c between null and 2")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(row, IsNil)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t1, t2, t3")
|
|
mustExecSQL(c, se, `
|
|
create table t1 (c1 int);
|
|
create table t2 (c2 int);
|
|
create table t3 (c3 int);`)
|
|
mustExecSQL(c, se, `
|
|
insert into t1 values (1), (2);
|
|
insert into t2 values (2);
|
|
insert into t3 values (3);`)
|
|
r = mustExecSQL(c, se, "select * from t1 left join t2 on t1.c1 = t2.c2 left join t3 on t1.c1 = t3.c3 order by t1.c1")
|
|
rows, err = GetRows(r)
|
|
c.Assert(err, IsNil)
|
|
matches(c, rows, [][]interface{}{{1, nil, nil}, {2, 2, nil}})
|
|
|
|
mustExecFailed(c, se, "select * from t1 left join t2 on t1.c1 = t3.c3 left join on t3 on t1.c1 = t2.c2")
|
|
|
|
// For issue 393
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, "create table t (b blob)")
|
|
mustExecSQL(c, se, `insert t values('\x01')`)
|
|
|
|
r = mustExecSQL(c, se, `select length(b) from t`)
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 3)
|
|
|
|
mustExecSQL(c, se, `select * from t1, t2 where t1.c1 is null`)
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestSubQuery(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_subquery"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
mustExecSQL(c, se, "create table if not exists t1 (c1 int, c2 int)")
|
|
mustExecSQL(c, se, "create table if not exists t2 (c1 int, c2 int)")
|
|
mustExecSQL(c, se, "insert into t1 values (1, 1), (2, 2)")
|
|
mustExecSQL(c, se, "insert into t2 values (1, 1), (1, 2)")
|
|
|
|
r := mustExecSQL(c, se, `select c1 from t1 where c1 = (select c2 from t2 where t1.c2 = t2.c2)`)
|
|
row, err := r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 1)
|
|
|
|
r = mustExecSQL(c, se, `select (select count(c1) from t2 where t2.c1 != t1.c2) from t1`)
|
|
rows, err := GetRows(r)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(rows, HasLen, 2)
|
|
match(c, rows[0], 0)
|
|
match(c, rows[1], 2)
|
|
|
|
mustExecMatch(c, se, "select a.c1, a.c2 from (select c1 as c1, c1 as c2 from t1) as a", [][]interface{}{{1, 1}, {2, 2}})
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestShow(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_show"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
mustExecSQL(c, se, "set global autocommit=1")
|
|
r := mustExecSQL(c, se, "show global variables where variable_name = 'autocommit'")
|
|
row, err := r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, "autocommit", "ON")
|
|
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, `create table if not exists t (c int) comment '注释'`)
|
|
r = mustExecSQL(c, se, `show columns from t`)
|
|
rows, err := GetRows(r)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(rows, HasLen, 1)
|
|
match(c, rows[0], "c", "int(11)", "YES", "", nil, "")
|
|
|
|
r = mustExecSQL(c, se, "show collation where Charset = 'utf8' and Collation = 'utf8_bin'")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, "utf8_bin", "utf8", 83, "", "Yes", 1)
|
|
|
|
r = mustExecSQL(c, se, "show tables")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(row.Data, HasLen, 1)
|
|
|
|
r = mustExecSQL(c, se, "show full tables")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(row.Data, HasLen, 2)
|
|
|
|
r = mustExecSQL(c, se, "show create table t")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(row.Data, HasLen, 2)
|
|
c.Assert(row.Data[0].GetString(), Equals, "t")
|
|
|
|
r = mustExecSQL(c, se, fmt.Sprintf("show table status from %s like 't';", dbName))
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(row.Data, HasLen, 18)
|
|
c.Assert(row.Data[0].GetString(), Equals, "t")
|
|
c.Assert(row.Data[17].GetString(), Equals, "注释")
|
|
|
|
r = mustExecSQL(c, se, "show databases like 'test'")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(row.Data, HasLen, 1)
|
|
c.Assert(row.Data[0].GetString(), Equals, "test")
|
|
|
|
r = mustExecSQL(c, se, "grant all on *.* to 'root'@'%'")
|
|
r = mustExecSQL(c, se, "show grants")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(row.Data, HasLen, 1)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestTimeFunc(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_time_func"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
last := time.Now().Format(types.TimeFormat)
|
|
r := mustExecSQL(c, se, "select now(), now(6), current_timestamp, current_timestamp(), current_timestamp(6), sysdate(), sysdate(6)")
|
|
row, err := r.Next()
|
|
c.Assert(err, IsNil)
|
|
for _, t := range row.Data {
|
|
n := t.GetMysqlTime()
|
|
c.Assert(n.String(), GreaterEqual, last)
|
|
}
|
|
|
|
last = time.Now().Format(types.DateFormat)
|
|
r = mustExecSQL(c, se, "select current_date, current_date(), curdate()")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
for _, t := range row.Data {
|
|
n := t.GetMysqlTime()
|
|
c.Assert(n.String(), GreaterEqual, last)
|
|
}
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestBit(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_bit"
|
|
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 bit(2))")
|
|
mustExecSQL(c, se, "insert into t values (0), (1), (2), (3)")
|
|
_, err := exec(se, "insert into t values (4)")
|
|
c.Assert(err, NotNil)
|
|
r := mustExecSQL(c, se, "select * from t where c1 = 2")
|
|
row, err := r.Next()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(row.Data[0].GetMysqlBit(), Equals, types.Bit{Value: 2, Width: 2})
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestEnum(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_enum"
|
|
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 (c enum('a', 'b', 'c'))")
|
|
mustExecSQL(c, se, "insert into t values ('a'), (2), ('c')")
|
|
r := mustExecSQL(c, se, "select * from t where c = 'a'")
|
|
row, err := r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, "a")
|
|
|
|
r = mustExecSQL(c, se, "select c + 1 from t where c = 2")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, "3")
|
|
|
|
mustExecSQL(c, se, "delete from t")
|
|
mustExecSQL(c, se, "insert into t values ()")
|
|
mustExecSQL(c, se, "insert into t values (null), ('1')")
|
|
r = mustExecSQL(c, se, "select c + 1 from t where c = 1")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, "2")
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestSet(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_set"
|
|
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 (c set('a', 'b', 'c'))")
|
|
mustExecSQL(c, se, "insert into t values ('a'), (2), ('c'), ('a,b'), ('b,a')")
|
|
r := mustExecSQL(c, se, "select * from t where c = 'a'")
|
|
row, err := r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, "a")
|
|
|
|
r = mustExecSQL(c, se, "select * from t where c = 'a,b'")
|
|
rows, err := GetRows(r)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(rows, HasLen, 2)
|
|
|
|
r = mustExecSQL(c, se, "select c + 1 from t where c = 2")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, "3")
|
|
|
|
mustExecSQL(c, se, "delete from t")
|
|
mustExecSQL(c, se, "insert into t values ()")
|
|
mustExecSQL(c, se, "insert into t values (null), ('1')")
|
|
r = mustExecSQL(c, se, "select c + 1 from t where c = 1")
|
|
row, err = r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, "2")
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestDatabase(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_database"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
// Test database.
|
|
mustExecSQL(c, se, "create database xxx")
|
|
mustExecSQL(c, se, "drop database xxx")
|
|
|
|
mustExecSQL(c, se, "drop database if exists xxx")
|
|
mustExecSQL(c, se, "create database xxx")
|
|
mustExecSQL(c, se, "create database if not exists xxx")
|
|
mustExecSQL(c, se, "drop database if exists xxx")
|
|
|
|
// Test schema.
|
|
mustExecSQL(c, se, "create schema xxx")
|
|
mustExecSQL(c, se, "drop schema xxx")
|
|
|
|
mustExecSQL(c, se, "drop schema if exists xxx")
|
|
mustExecSQL(c, se, "create schema xxx")
|
|
mustExecSQL(c, se, "create schema if not exists xxx")
|
|
mustExecSQL(c, se, "drop schema if exists xxx")
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestWhereLike(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_where_like"
|
|
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(c int, index(c))")
|
|
mustExecSQL(c, se, "insert into t values (1),(2),(3),(-11),(11),(123),(211),(210)")
|
|
mustExecSQL(c, se, "insert into t values ()")
|
|
|
|
r := mustExecSQL(c, se, "select c from t where c like '%1%'")
|
|
rows, err := GetRows(r)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(rows, HasLen, 6)
|
|
|
|
mustExecSQL(c, se, "select c from t where c like binary('abc')")
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestDefaultFlenBug(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
// If set unspecified column flen to 0, it will cause bug in union.
|
|
// This test is used to prevent the bug reappear.
|
|
dbName := "test_default_flen_bug"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
mustExecSQL(c, se, "create table t1 (c double);")
|
|
mustExecSQL(c, se, "create table t2 (c double);")
|
|
mustExecSQL(c, se, "insert into t1 value (73);")
|
|
mustExecSQL(c, se, "insert into t2 value (930);")
|
|
// The data in the second src will be casted as the type of the first src.
|
|
// If use flen=0, it will be truncated.
|
|
r := mustExecSQL(c, se, "select c from t1 union (select c from t2) order by c;")
|
|
rows, err := GetRows(r)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(rows, HasLen, 2)
|
|
c.Assert(rows[1][0].GetFloat64(), Equals, float64(930))
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
c.Assert(err, IsNil)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestExecRestrictedSQL(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_exec_restricted_sql"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName).(*session)
|
|
r, _, err := se.ExecRestrictedSQL(se, "select 1;")
|
|
c.Assert(err, IsNil)
|
|
c.Assert(len(r), Equals, 1)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestGroupBy(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_groupby"
|
|
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 int)")
|
|
mustExecSQL(c, se, "insert into t values (1,1), (2,2), (1,2), (1,3)")
|
|
mustExecMatch(c, se, "select nullif (count(*), 2);", [][]interface{}{{1}})
|
|
mustExecMatch(c, se, "select 1 as a, sum(c1) as a from t group by a", [][]interface{}{{1, 5}})
|
|
mustExecMatch(c, se, "select c1 as a, 1 as a, sum(c1) as a from t group by a", [][]interface{}{{1, 1, 5}})
|
|
mustExecMatch(c, se, "select c1 as a, 1 as a, c2 as a from t group by a;", [][]interface{}{{1, 1, 1}})
|
|
mustExecMatch(c, se, "select c1 as c2, sum(c1) as c2 from t group by c2;", [][]interface{}{{1, 1}, {2, 3}, {1, 1}})
|
|
|
|
mustExecMatch(c, se, "select c1 as c2, c2 from t group by c2 + 1", [][]interface{}{{1, 1}, {2, 2}, {1, 3}})
|
|
mustExecMatch(c, se, "select c1 as c2, count(c1) from t group by c2", [][]interface{}{{1, 1}, {2, 2}, {1, 1}})
|
|
mustExecMatch(c, se, "select t.c1, c1 from t group by c1", [][]interface{}{{1, 1}, {2, 2}})
|
|
mustExecMatch(c, se, "select t.c1 as a, c1 as a from t group by a", [][]interface{}{{1, 1}, {2, 2}})
|
|
|
|
mustExecFailed(c, se, "select c1 as a, c2 as a from t group by a")
|
|
mustExecFailed(c, se, "select c1 as c2, c2 from t group by c2")
|
|
mustExecFailed(c, se, "select sum(c1) as a from t group by a")
|
|
mustExecFailed(c, se, "select sum(c1) as a from t group by a + 1")
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestOrderBy(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_order_by"
|
|
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 int, c3 varchar(20))")
|
|
mustExecSQL(c, se, "insert into t values (1, 2, 'abc'), (2, 1, 'bcd')")
|
|
|
|
// Fix issue https://github.com/pingcap/tidb/issues/337
|
|
mustExecMatch(c, se, "select c1 as a, c1 as b from t order by c1", [][]interface{}{{1, 1}, {2, 2}})
|
|
|
|
mustExecMatch(c, se, "select c1 as a, t.c1 as a from t order by a desc", [][]interface{}{{2, 2}, {1, 1}})
|
|
mustExecMatch(c, se, "select c1 as c2 from t order by c2", [][]interface{}{{1}, {2}})
|
|
mustExecMatch(c, se, "select sum(c1) from t order by sum(c1)", [][]interface{}{{3}})
|
|
mustExecMatch(c, se, "select c1 as c2 from t order by c2 + 1", [][]interface{}{{2}, {1}})
|
|
|
|
// Order by position
|
|
mustExecMatch(c, se, "select * from t order by 1", [][]interface{}{{1, 2, []byte("abc")}, {2, 1, []byte("bcd")}})
|
|
mustExecMatch(c, se, "select * from t order by 2", [][]interface{}{{2, 1, []byte("bcd")}, {1, 2, []byte("abc")}})
|
|
mustExecFailed(c, se, "select * from t order by 0")
|
|
mustExecFailed(c, se, "select * from t order by 4")
|
|
|
|
mustExecFailed(c, se, "select c1 as a, c2 as a from t order by a")
|
|
|
|
mustExecFailed(c, se, "(select c1 as c2, c2 from t) union (select c1, c2 from t) order by c2")
|
|
mustExecFailed(c, se, "(select c1 as c2, c2 from t) union (select c1, c2 from t) order by c1")
|
|
|
|
// Ordery by binary
|
|
mustExecMatch(c, se, "select c1, c3 from t order by binary c1 desc", [][]interface{}{{2, []byte("bcd")}, {1, []byte("abc")}})
|
|
mustExecMatch(c, se, "select c1, c2 from t order by binary c3", [][]interface{}{{1, 2}, {2, 1}})
|
|
|
|
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)
|
|
mustExecSQL(c, se, "drop table if exists t")
|
|
mustExecSQL(c, se, "create table t (c1 int, c2 int, c3 int)")
|
|
mustExecSQL(c, se, "insert into t values (1,2,3), (2, 3, 1), (3, 1, 2)")
|
|
|
|
mustExecMatch(c, se, "select c1 as c2, c3 from t having c2 = 2", [][]interface{}{{2, 1}})
|
|
mustExecMatch(c, se, "select c1 as c2, c3 from t group by c2 having c2 = 2;", [][]interface{}{{1, 3}})
|
|
mustExecMatch(c, se, "select c1 as c2, c3 from t group by c2 having sum(c2) = 2;", [][]interface{}{{1, 3}})
|
|
mustExecMatch(c, se, "select c1 as c2, c3 from t group by c3 having sum(c2) = 2;", [][]interface{}{{1, 3}})
|
|
mustExecMatch(c, se, "select c1 as c2, c3 from t group by c3 having sum(0) + c2 = 2;", [][]interface{}{{2, 1}})
|
|
mustExecMatch(c, se, "select c1 as a from t having c1 = 1;", [][]interface{}{{1}})
|
|
mustExecMatch(c, se, "select t.c1 from t having c1 = 1;", [][]interface{}{{1}})
|
|
mustExecMatch(c, se, "select a.c1 from t as a having c1 = 1;", [][]interface{}{{1}})
|
|
mustExecMatch(c, se, "select c1 as a from t group by c3 having sum(a) = 1;", [][]interface{}{{1}})
|
|
mustExecMatch(c, se, "select c1 as a from t group by c3 having sum(a) + a = 2;", [][]interface{}{{1}})
|
|
mustExecMatch(c, se, "select a.c1 as c, a.c1 as d from t as a, t as b having c1 = 1 limit 1;", [][]interface{}{{1, 1}})
|
|
|
|
mustExecMatch(c, se, "select sum(c1) from t group by c1 having sum(c1)", [][]interface{}{{1}, {2}, {3}})
|
|
mustExecMatch(c, se, "select sum(c1) - 1 from t group by c1 having sum(c1) - 1", [][]interface{}{{1}, {2}})
|
|
mustExecMatch(c, se, "select 1 from t group by c1 having sum(abs(c2 + c3)) = c1", [][]interface{}{{1}})
|
|
|
|
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) TestResultType(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
// Testcase for https://github.com/pingcap/tidb/issues/325
|
|
dbName := "test_result_type"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
rs := mustExecSQL(c, se, `select cast(null as char(30))`)
|
|
c.Assert(rs, NotNil)
|
|
row, err := rs.Next()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(row.Data[0].GetValue(), IsNil)
|
|
fs, err := rs.Fields()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(fs[0].Column.FieldType.Tp, Equals, mysql.TypeString)
|
|
|
|
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) TestBuiltin(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_builtin"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
// Testcase for https://github.com/pingcap/tidb/issues/382
|
|
mustExecFailed(c, se, `select cast("xxx 10:10:10" as datetime)`)
|
|
mustExecMatch(c, se, "select locate('bar', 'foobarbar')", [][]interface{}{{4}})
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestFieldText(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_field_text"
|
|
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 int)")
|
|
cases := []struct {
|
|
sql string
|
|
field string
|
|
}{
|
|
{"select distinct(a) from t", "a"},
|
|
{"select (1)", "1"},
|
|
{"select (1+1)", "(1+1)"},
|
|
{"select a from t", "a"},
|
|
{"select ((a+1)) from t", "((a+1))"},
|
|
}
|
|
for _, v := range cases {
|
|
results, err := se.Execute(v.sql)
|
|
c.Assert(err, IsNil)
|
|
result := results[0]
|
|
fields, err := result.Fields()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(fields[0].ColumnAsName.O, Equals, v.field)
|
|
}
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIndexPointLookup(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_index_point_lookup"
|
|
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 int)")
|
|
mustExecSQL(c, se, "insert t values (1), (2), (3)")
|
|
mustExecMatch(c, se, "select * from t where a = '1.1';", [][]interface{}{})
|
|
mustExecMatch(c, se, "select * from t where a > '1.1';", [][]interface{}{{2}, {3}})
|
|
mustExecMatch(c, se, "select * from t where a = '2';", [][]interface{}{{2}})
|
|
mustExecMatch(c, se, "select * from t where a = 3;", [][]interface{}{{3}})
|
|
mustExecMatch(c, se, "select * from t where a = 4;", [][]interface{}{})
|
|
mustExecSQL(c, se, "drop table t")
|
|
|
|
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)
|
|
}
|
|
|
|
// 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) TestRetryPreparedStmt(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_retry_prepare_stmt"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
se1 := newSession(c, s.store, dbName)
|
|
se2 := 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 (c1 int, c2 int, c3 int)")
|
|
mustExecSQL(c, se, "insert t values (11, 2, 3)")
|
|
|
|
mustExecSQL(c, se1, "begin")
|
|
mustExecSQL(c, se1, "update t set c2=? where c1=11;", 21)
|
|
|
|
mustExecSQL(c, se2, "begin")
|
|
mustExecSQL(c, se2, "update t set c2=? where c1=11", 22)
|
|
mustExecSQL(c, se2, "commit")
|
|
|
|
mustExecSQL(c, se1, "commit")
|
|
|
|
se3 := newSession(c, s.store, dbName)
|
|
r := mustExecSQL(c, se3, "select c2 from t where c1=11")
|
|
row, err := r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 21)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestSleep(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_sleep"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
|
|
mustExecSQL(c, se, "select sleep(0.01);")
|
|
mustExecSQL(c, se, "drop table if exists t;")
|
|
mustExecSQL(c, se, "create table t (a int);")
|
|
mustExecSQL(c, se, "insert t values (sleep(0.02));")
|
|
r := mustExecSQL(c, se, "select * from t;")
|
|
row, err := r.Next()
|
|
c.Assert(err, IsNil)
|
|
match(c, row.Data, 0)
|
|
|
|
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 := newStoreWithBootstrap(c, dbName)
|
|
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))
|
|
|
|
err = se.Close()
|
|
c.Assert(err, IsNil)
|
|
err = se1.Close()
|
|
c.Assert(err, IsNil)
|
|
err = se2.Close()
|
|
c.Assert(err, IsNil)
|
|
sessionctx.GetDomain(ctx).Close()
|
|
err = store.Close()
|
|
c.Assert(err, IsNil)
|
|
localstore.MockRemoteStore = false
|
|
}
|
|
|
|
// Testcase for session
|
|
func (s *testSessionSuite) TestSession(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_session"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
mustExecSQL(c, se, "ROLLBACK;")
|
|
|
|
err := se.Close()
|
|
c.Assert(err, IsNil)
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestSessionAuth(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_session_auth"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
defer se.Close()
|
|
c.Assert(se.Auth("Any not exist username with zero password! @anyhost", []byte(""), []byte("")), IsFalse)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestErrorRollback(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_error_rollback"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
s1 := newSession(c, s.store, dbName)
|
|
|
|
defer s1.Close()
|
|
|
|
mustExecSQL(c, s1, "drop table if exists t_rollback")
|
|
mustExecSQL(c, s1, "create table t_rollback (c1 int, c2 int, primary key(c1))")
|
|
|
|
_, err := s1.Execute("insert into t_rollback values (0, 0)")
|
|
c.Assert(err, IsNil)
|
|
|
|
var wg sync.WaitGroup
|
|
cnt := 4
|
|
wg.Add(cnt)
|
|
num := 100
|
|
|
|
for i := 0; i < cnt; i++ {
|
|
go func() {
|
|
defer wg.Done()
|
|
se := newSession(c, s.store, dbName)
|
|
// retry forever
|
|
se.(*session).unlimitedRetryCount = true
|
|
defer se.Close()
|
|
|
|
for j := 0; j < num; j++ {
|
|
// force generate a txn in session for later insert use.
|
|
se.(*session).GetTxn(false)
|
|
|
|
se.Execute("insert into t_rollback values (1, 1)")
|
|
|
|
_, err1 := se.Execute("update t_rollback set c2 = c2 + 1 where c1 = 0")
|
|
c.Assert(err1, IsNil)
|
|
}
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
mustExecMatch(c, s1, "select c2 from t_rollback where c1 = 0", [][]interface{}{{cnt * num}})
|
|
|
|
mustExecSQL(c, s1, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestMultiColumnIndex(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_multi_column_index"
|
|
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 int);")
|
|
mustExecSQL(c, se, "create index idx_c1_c2 on t (c1, c2)")
|
|
mustExecSQL(c, se, "insert into t values (1, 5)")
|
|
|
|
sql := "select c1 from t where c1 in (1) and c2 < 10"
|
|
checkPlan(c, se, sql, "Index(t.idx_c1_c2)[[1 -inf,1 10)]->Projection")
|
|
mustExecMatch(c, se, sql, [][]interface{}{{1}})
|
|
|
|
sql = "select c1 from t where c1 in (1) and c2 > 3"
|
|
checkPlan(c, se, sql, "Index(t.idx_c1_c2)[(1 3,1 +inf]]->Projection")
|
|
mustExecMatch(c, se, sql, [][]interface{}{{1}})
|
|
|
|
sql = "select c1 from t where c1 in (1) and c2 < 5.1"
|
|
checkPlan(c, se, sql, "Index(t.idx_c1_c2)[[1 -inf,1 5]]->Projection")
|
|
mustExecMatch(c, se, sql, [][]interface{}{{1}})
|
|
|
|
sql = "select c1 from t where c1 in (1.1) and c2 > 3"
|
|
checkPlan(c, se, sql, "Index(t.idx_c1_c2)[]->Projection")
|
|
mustExecMatch(c, se, sql, [][]interface{}{})
|
|
|
|
// Test varchar type.
|
|
mustExecSQL(c, se, "drop table t;")
|
|
mustExecSQL(c, se, "create table t (id int unsigned primary key auto_increment, c1 varchar(64), c2 varchar(64), index c1_c2 (c1, c2));")
|
|
mustExecSQL(c, se, "insert into t (c1, c2) values ('abc', 'def')")
|
|
sql = "select c1 from t where c1 = 'abc'"
|
|
mustExecMatch(c, se, sql, [][]interface{}{{[]byte("abc")}})
|
|
|
|
mustExecSQL(c, se, "insert into t (c1, c2) values ('abc', 'xyz')")
|
|
mustExecSQL(c, se, "insert into t (c1, c2) values ('abd', 'abc')")
|
|
mustExecSQL(c, se, "insert into t (c1, c2) values ('abd', 'def')")
|
|
sql = "select c1 from t where c1 >= 'abc' and c2 = 'def'"
|
|
mustExecMatch(c, se, sql, [][]interface{}{{[]byte("abc")}, {[]byte("abd")}})
|
|
|
|
sql = "select c1, c2 from t where c1 = 'abc' and id < 2"
|
|
mustExecMatch(c, se, sql, [][]interface{}{{[]byte("abc"), []byte("def")}})
|
|
|
|
err := se.Close()
|
|
c.Assert(err, IsNil)
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestSubstringIndexExpr(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_substring_index_expr"
|
|
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 (c varchar(128));")
|
|
mustExecSQL(c, se, `insert into t values ("www.pingcap.com");`)
|
|
mustExecMatch(c, se, "SELECT DISTINCT SUBSTRING_INDEX(c, '.', 2) from t;", [][]interface{}{{"www.pingcap"}})
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestIndexMaxLength(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_index_max_length"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
mustExecSQL(c, se, "drop table if exists t;")
|
|
|
|
// create simple index at table creation
|
|
_, err := exec(se, "create table t (c1 varchar(3073), index(c1));")
|
|
// ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
|
|
c.Assert(err, NotNil)
|
|
|
|
// create simple index after table creation
|
|
mustExecSQL(c, se, "create table t (c1 varchar(3073));")
|
|
_, err = exec(se, "create index idx_c1 on t(c1) ")
|
|
// ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
|
|
c.Assert(err, NotNil)
|
|
|
|
// create compound index at table creation
|
|
mustExecSQL(c, se, "drop table if exists t;")
|
|
_, err = exec(se, "create table t (c1 varchar(3072), c2 varchar(1), index(c1, c2));")
|
|
// ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
|
|
c.Assert(err, NotNil)
|
|
|
|
_, err = exec(se, "create table t (c1 varchar(3072), c2 char(1), index(c1, c2));")
|
|
// ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
|
|
c.Assert(err, NotNil)
|
|
|
|
_, err = exec(se, "create table t (c1 varchar(3072), c2 char, index(c1, c2));")
|
|
// ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
|
|
c.Assert(err, NotNil)
|
|
|
|
_, err = exec(se, "create table t (c1 varchar(3072), c2 date, index(c1, c2));")
|
|
// ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
|
|
c.Assert(err, NotNil)
|
|
|
|
_, err = exec(se, "create table t (c1 varchar(3068), c2 timestamp(1), index(c1, c2));")
|
|
// ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
|
|
c.Assert(err, NotNil)
|
|
|
|
_, err = exec(se, "create table t (c1 varchar(3068), c2 bit(26), index(c1, c2));")
|
|
// ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
|
|
c.Assert(err, NotNil)
|
|
|
|
// create compound index after table creation
|
|
mustExecSQL(c, se, "create table t (c1 varchar(3072), c2 varchar(1));")
|
|
_, err = exec(se, "create index idx_c1_c2 on t(c1, c2);")
|
|
// ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
|
|
c.Assert(err, NotNil)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t;")
|
|
mustExecSQL(c, se, "create table t (c1 varchar(3072), c2 char(1));")
|
|
_, err = exec(se, "create index idx_c1_c2 on t(c1, c2);")
|
|
// ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
|
|
c.Assert(err, NotNil)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t;")
|
|
mustExecSQL(c, se, "create table t (c1 varchar(3072), c2 char);")
|
|
_, err = exec(se, "create index idx_c1_c2 on t(c1, c2);")
|
|
// ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
|
|
c.Assert(err, NotNil)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t;")
|
|
mustExecSQL(c, se, "create table t (c1 varchar(3072), c2 date);")
|
|
_, err = exec(se, "create index idx_c1_c2 on t(c1, c2);")
|
|
// ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
|
|
c.Assert(err, NotNil)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t;")
|
|
mustExecSQL(c, se, "create table t (c1 varchar(3068), c2 timestamp(1));")
|
|
_, err = exec(se, "create index idx_c1_c2 on t(c1, c2);")
|
|
// ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
|
|
c.Assert(err, NotNil)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t;")
|
|
mustExecSQL(c, se, "create table t (c1 varchar(3068), c2 bit(26));")
|
|
_, err = exec(se, "create index idx_c1_c2 on t(c1, c2);")
|
|
// ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
|
|
c.Assert(err, NotNil)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestSpecifyIndexPrefixLength(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_specify_index_prefix_length"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
mustExecSQL(c, se, "drop table if exists t;")
|
|
|
|
_, err := exec(se, "create table t (c1 char, index(c1(3)));")
|
|
// ERROR 1089 (HY000): Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys
|
|
c.Assert(err, NotNil)
|
|
|
|
_, err = exec(se, "create table t (c1 int, index(c1(3)));")
|
|
// ERROR 1089 (HY000): Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys
|
|
c.Assert(err, NotNil)
|
|
|
|
_, err = exec(se, "create table t (c1 bit(10), index(c1(3)));")
|
|
// ERROR 1089 (HY000): Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys
|
|
c.Assert(err, NotNil)
|
|
|
|
mustExecSQL(c, se, "create table t (c1 char, c2 int, c3 bit(10));")
|
|
|
|
_, err = exec(se, "create index idx_c1 on t (c1(3));")
|
|
// ERROR 1089 (HY000): Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys
|
|
c.Assert(err, NotNil)
|
|
|
|
_, err = exec(se, "create index idx_c1 on t (c2(3));")
|
|
// ERROR 1089 (HY000): Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys
|
|
c.Assert(err, NotNil)
|
|
|
|
_, err = exec(se, "create index idx_c1 on t (c3(3));")
|
|
// ERROR 1089 (HY000): Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys
|
|
c.Assert(err, NotNil)
|
|
|
|
mustExecSQL(c, se, "drop table if exists t;")
|
|
|
|
_, err = exec(se, "create table t (c1 int, c2 blob, c3 varchar(64), index(c2));")
|
|
// ERROR 1170 (42000): BLOB/TEXT column 'c2' used in key specification without a key length
|
|
c.Assert(err, NotNil)
|
|
|
|
mustExecSQL(c, se, "create table t (c1 int, c2 blob, c3 varchar(64));")
|
|
_, err = exec(se, "create index idx_c1 on t (c2);")
|
|
// ERROR 1170 (42000): BLOB/TEXT column 'c2' used in key specification without a key length
|
|
c.Assert(err, NotNil)
|
|
|
|
_, err = exec(se, "create index idx_c1 on t (c2(555555));")
|
|
// ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
|
|
c.Assert(err, NotNil)
|
|
|
|
_, err = exec(se, "create index idx_c1 on t (c1(5))")
|
|
// ERROR 1089 (HY000): Incorrect prefix key;
|
|
// the used key part isn't a string, the used length is longer than the key part,
|
|
// or the storage engine doesn't support unique prefix keys
|
|
c.Assert(err, NotNil)
|
|
|
|
mustExecSQL(c, se, "create index idx_c1 on t (c1);")
|
|
mustExecSQL(c, se, "create index idx_c2 on t (c2(3));")
|
|
mustExecSQL(c, se, "create unique index idx_c3 on t (c3(5));")
|
|
|
|
mustExecSQL(c, se, "insert into t values (3, 'abc', 'def');")
|
|
sql := "select c2 from t where c2 = 'abc';"
|
|
mustExecMatch(c, se, sql, [][]interface{}{{[]byte("abc")}})
|
|
|
|
mustExecSQL(c, se, "insert into t values (4, 'abcd', 'xxx');")
|
|
mustExecSQL(c, se, "insert into t values (4, 'abcf', 'yyy');")
|
|
sql = "select c2 from t where c2 = 'abcf';"
|
|
mustExecMatch(c, se, sql, [][]interface{}{{[]byte("abcf")}})
|
|
sql = "select c2 from t where c2 = 'abcd';"
|
|
mustExecMatch(c, se, sql, [][]interface{}{{[]byte("abcd")}})
|
|
|
|
mustExecSQL(c, se, "insert into t values (4, 'ignore', 'abcdeXXX');")
|
|
_, err = exec(se, "insert into t values (5, 'ignore', 'abcdeYYY');")
|
|
// ERROR 1062 (23000): Duplicate entry 'abcde' for key 'idx_c3'
|
|
c.Assert(err, NotNil)
|
|
sql = "select c3 from t where c3 = 'abcde';"
|
|
mustExecMatch(c, se, sql, [][]interface{}{})
|
|
|
|
mustExecSQL(c, se, "delete from t where c3 = 'abcdeXXX';")
|
|
mustExecSQL(c, se, "delete from t where c2 = 'abc';")
|
|
|
|
mustExecMatch(c, se, "select c2 from t where c2 > 'abcd';", [][]interface{}{{[]byte("abcf")}})
|
|
mustExecMatch(c, se, "select c2 from t where c2 < 'abcf';", [][]interface{}{{[]byte("abcd")}})
|
|
mustExecMatch(c, se, "select c2 from t where c2 >= 'abcd';", [][]interface{}{{[]byte("abcd")}, {[]byte("abcf")}})
|
|
mustExecMatch(c, se, "select c2 from t where c2 <= 'abcf';", [][]interface{}{{[]byte("abcd")}, {[]byte("abcf")}})
|
|
mustExecMatch(c, se, "select c2 from t where c2 != 'abc';", [][]interface{}{{[]byte("abcd")}, {[]byte("abcf")}})
|
|
mustExecMatch(c, se, "select c2 from t where c2 != 'abcd';", [][]interface{}{{[]byte("abcf")}})
|
|
|
|
mustExecSQL(c, se, "drop table if exists t1;")
|
|
mustExecSQL(c, se, "create table t1 (a int, b char(255), key(a, b(20)));")
|
|
mustExecSQL(c, se, "insert into t1 values (0, '1');")
|
|
mustExecSQL(c, se, "update t1 set b = b + 1 where a = 0;")
|
|
mustExecMatch(c, se, "select b from t1 where a = 0;", [][]interface{}{{[]byte("2")}})
|
|
|
|
// test union index.
|
|
mustExecSQL(c, se, "drop table if exists t;")
|
|
mustExecSQL(c, se, "create table t (a text, b text, c int, index (a(3), b(3), c));")
|
|
mustExecSQL(c, se, "insert into t values ('abc', 'abcd', 1);")
|
|
mustExecSQL(c, se, "insert into t values ('abcx', 'abcf', 2);")
|
|
mustExecSQL(c, se, "insert into t values ('abcy', 'abcf', 3);")
|
|
mustExecSQL(c, se, "insert into t values ('bbc', 'abcd', 4);")
|
|
mustExecSQL(c, se, "insert into t values ('bbcz', 'abcd', 5);")
|
|
mustExecSQL(c, se, "insert into t values ('cbck', 'abd', 6);")
|
|
mustExecMatch(c, se, "select c from t where a = 'abc' and b <= 'abc';", [][]interface{}{})
|
|
mustExecMatch(c, se, "select c from t where a = 'abc' and b <= 'abd';", [][]interface{}{{1}})
|
|
mustExecMatch(c, se, "select c from t where a < 'cbc' and b > 'abcd';", [][]interface{}{{2}, {3}})
|
|
mustExecMatch(c, se, "select c from t where a <= 'abd' and b > 'abc';", [][]interface{}{{1}, {2}, {3}})
|
|
mustExecMatch(c, se, "select c from t where a < 'bbcc' and b = 'abcd';", [][]interface{}{{1}, {4}})
|
|
mustExecMatch(c, se, "select c from t where a > 'bbcf';", [][]interface{}{{5}, {6}})
|
|
|
|
err = se.Close()
|
|
c.Assert(err, IsNil)
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestJoinSubquery(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
dbName := "test_join_subquery"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
mustExecSQL(c, se, "CREATE TABLE table1 (id INTEGER key AUTO_INCREMENT, data VARCHAR(30))")
|
|
mustExecSQL(c, se, "CREATE TABLE table2 (id INTEGER key AUTO_INCREMENT, data VARCHAR(30), t1id INTEGER)")
|
|
sqlTxt := `SELECT table1.id AS table1_id, table1.data AS table1_data FROM
|
|
table1 INNER JOIN (
|
|
SELECT table2.id AS id, table2.data AS data, table2.t1id AS t1id FROM table2
|
|
) AS anon_1 ON table1.id = anon_1.t1id;`
|
|
mustExecSQL(c, se, sqlTxt)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestGlobalVarAccessor(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
|
|
varName := "max_allowed_packet"
|
|
varValue := "67108864" // This is the default value for max_allowed_packet
|
|
varValue1 := "4194305"
|
|
varValue2 := "4194306"
|
|
|
|
dbName := "test_global_var_accessor"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName).(*session)
|
|
// Get globalSysVar twice and get the same value
|
|
v, err := se.GetGlobalSysVar(varName)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(v, Equals, varValue)
|
|
v, err = se.GetGlobalSysVar(varName)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(v, Equals, varValue)
|
|
// Set global var to another value
|
|
err = se.SetGlobalSysVar(varName, varValue1)
|
|
c.Assert(err, IsNil)
|
|
v, err = se.GetGlobalSysVar(varName)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(v, Equals, varValue1)
|
|
c.Assert(se.CommitTxn(), IsNil)
|
|
|
|
// Change global variable value in another session
|
|
se1 := newSession(c, s.store, dbName).(*session)
|
|
v, err = se1.GetGlobalSysVar(varName)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(v, Equals, varValue1)
|
|
err = se1.SetGlobalSysVar(varName, varValue2)
|
|
c.Assert(err, IsNil)
|
|
v, err = se1.GetGlobalSysVar(varName)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(v, Equals, varValue2)
|
|
c.Assert(se1.CommitTxn(), IsNil)
|
|
|
|
// Make sure the change is visible to any client that accesses that global variable.
|
|
v, err = se.GetGlobalSysVar(varName)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(v, Equals, varValue2)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func checkPlan(c *C, se Session, sql, explain string) {
|
|
ctx := se.(context.Context)
|
|
stmts, err := Parse(ctx, sql)
|
|
c.Assert(err, IsNil)
|
|
stmt := stmts[0]
|
|
is := sessionctx.GetDomain(ctx).InfoSchema()
|
|
err = plan.PrepareStmt(is, ctx, stmt)
|
|
c.Assert(err, IsNil)
|
|
p, err := plan.Optimize(ctx, stmt, is)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(plan.ToString(p), Equals, explain)
|
|
}
|
|
|
|
func mustExecMultiSQL(c *C, se Session, sql string) {
|
|
ss := strings.Split(sql, "\n")
|
|
for _, s := range ss {
|
|
s = strings.TrimSpace(s)
|
|
if len(s) == 0 {
|
|
continue
|
|
}
|
|
mustExecSQL(c, se, s)
|
|
}
|
|
}
|
|
|
|
func (s *testSessionSuite) TestSqlLogicTestCase(c *C) {
|
|
initSQL := `
|
|
CREATE TABLE tab1(pk INTEGER PRIMARY KEY, col0 INTEGER, col1 FLOAT)
|
|
INSERT INTO tab1 VALUES(0,26,690.51)
|
|
CREATE INDEX idx_tab1_1 on tab1 (col1)`
|
|
dbName := "test_sql_logic_test_case"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
mustExecMultiSQL(c, se, initSQL)
|
|
|
|
sql := "SELECT col0 FROM tab1 WHERE 71*22 >= col1"
|
|
mustExecMatch(c, se, sql, [][]interface{}{{"26"}})
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestXAggregateWithIndexScan(c *C) {
|
|
initSQL := `
|
|
drop table IF EXISTS t;
|
|
CREATE TABLE t(c INT, index cidx (c));
|
|
INSERT INTO t VALUES(1), (null), (2);`
|
|
dbName := "test_xaggregate_with_index_scan"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
mustExecMultiSQL(c, se, initSQL)
|
|
sql := "SELECT COUNT(c) FROM t WHERE c > 0;"
|
|
mustExecMatch(c, se, sql, [][]interface{}{{"2"}})
|
|
|
|
initSQL = `
|
|
Drop table if exists tab1;
|
|
CREATE TABLE tab1(pk INTEGER PRIMARY KEY, col0 INTEGER, col1 FLOAT, col2 TEXT, col3 INTEGER, col4 FLOAT, col5 TEXT);
|
|
CREATE INDEX idx_tab1_3 on tab1 (col3);
|
|
INSERT INTO tab1 VALUES(0,656,638.70,'zsiag',614,231.92,'dkfhp');
|
|
`
|
|
mustExecMultiSQL(c, se, initSQL)
|
|
sql = "SELECT DISTINCT + - COUNT( col3 ) AS col1 FROM tab1 AS cor0 WHERE col3 > 0;"
|
|
mustExecMatch(c, se, sql, [][]interface{}{{"-1"}})
|
|
|
|
sql = "SELECT DISTINCT + - COUNT( col3 ) AS col1 FROM tab1 AS cor0 WHERE col3 > 0 group by col0;"
|
|
mustExecMatch(c, se, sql, [][]interface{}{{"-1"}})
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
// Select with groupby but without aggregate function.
|
|
func (s *testSessionSuite) TestXAggregateWithoutAggFunc(c *C) {
|
|
// TableScan
|
|
initSQL := `
|
|
drop table IF EXISTS t;
|
|
CREATE TABLE t (c INT);
|
|
INSERT INTO t VALUES(1), (2), (3), (3);`
|
|
dbName := "test_xaggregate_without_agg_func"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
mustExecMultiSQL(c, se, initSQL)
|
|
sql := "SELECT 18 FROM t group by c;"
|
|
mustExecMatch(c, se, sql, [][]interface{}{{"18"}, {"18"}, {"18"}})
|
|
|
|
// IndexScan
|
|
initSQL = `
|
|
drop table IF EXISTS t;
|
|
CREATE TABLE t(c INT, index cidx (c));
|
|
INSERT INTO t VALUES(1), (2), (3), (3);`
|
|
mustExecMultiSQL(c, se, initSQL)
|
|
sql = "SELECT 18 FROM t where c > 1 group by c;"
|
|
mustExecMatch(c, se, sql, [][]interface{}{{"18"}, {"18"}})
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
// Test select with having.
|
|
// Move from executor to prevent from using mock-tikv.
|
|
func (s *testSessionSuite) TestSelectHaving(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
table := "select_having_test"
|
|
initSQL := fmt.Sprintf(`use test;
|
|
drop table if exists %s;
|
|
create table %s(id int not null default 1, name varchar(255), PRIMARY KEY(id));
|
|
insert INTO %s VALUES (1, "hello");
|
|
insert into %s VALUES (2, "hello");`,
|
|
table, table, table, table)
|
|
dbName := "test_select_having"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
mustExecMultiSQL(c, se, initSQL)
|
|
sql := "select id, name from select_having_test where id in (1,3) having name like 'he%';"
|
|
mustExecMatch(c, se, sql, [][]interface{}{{"1", fmt.Sprintf("%v", []byte("hello"))}})
|
|
mustExecMultiSQL(c, se, "select * from select_having_test group by id having null is not null;")
|
|
mustExecMultiSQL(c, se, "drop table select_having_test")
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
func (s *testSessionSuite) TestQueryString(c *C) {
|
|
dbName := "test_query_string"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
_, err := se.Execute("create table mutil1 (a int);create table multi2 (a int)")
|
|
c.Assert(err, IsNil)
|
|
ctx := se.(context.Context)
|
|
queryStr := ctx.Value(context.QueryString)
|
|
c.Assert(queryStr, Equals, "create table multi2 (a int)")
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
// Test that the auto_increment ID does not reuse the old table's allocator.
|
|
func (s *testSessionSuite) TestTruncateAlloc(c *C) {
|
|
dbName := "test_truncate_alloc"
|
|
dropDBSQL := fmt.Sprintf("drop database %s;", dbName)
|
|
se := newSession(c, s.store, dbName)
|
|
_, err := se.Execute("create table truncate_id (a int primary key auto_increment)")
|
|
c.Assert(err, IsNil)
|
|
mustExecute(se, "insert truncate_id values (), (), (), (), (), (), (), (), (), ()")
|
|
mustExecute(se, "truncate table truncate_id")
|
|
mustExecute(se, "insert truncate_id values (), (), (), (), (), (), (), (), (), ()")
|
|
rset := mustExecSQL(c, se, "select a from truncate_id where a > 11")
|
|
row, err := rset.Next()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(row, IsNil)
|
|
|
|
mustExecSQL(c, se, dropDBSQL)
|
|
}
|
|
|
|
// Test infomation_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)
|
|
}
|