342 lines
9.7 KiB
Go
342 lines
9.7 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 server
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/go-sql-driver/mysql"
|
|
. "github.com/pingcap/check"
|
|
tmysql "github.com/pingcap/tidb/mysql"
|
|
)
|
|
|
|
func TestT(t *testing.T) {
|
|
TestingT(t)
|
|
}
|
|
|
|
var regression = true
|
|
|
|
var dsn = "root@tcp(localhost:4001)/test?strict=true"
|
|
|
|
func runTests(c *C, dsn string, tests ...func(dbt *DBTest)) {
|
|
db, err := sql.Open("mysql", dsn)
|
|
c.Assert(err, IsNil, Commentf("Error connecting"))
|
|
defer db.Close()
|
|
|
|
db.Exec("DROP TABLE IF EXISTS test")
|
|
|
|
dbt := &DBTest{c, db}
|
|
for _, test := range tests {
|
|
test(dbt)
|
|
dbt.db.Exec("DROP TABLE IF EXISTS test")
|
|
}
|
|
}
|
|
|
|
type DBTest struct {
|
|
*C
|
|
db *sql.DB
|
|
}
|
|
|
|
func (dbt *DBTest) fail(method, query string, err error) {
|
|
if len(query) > 300 {
|
|
query = "[query too large to print]"
|
|
}
|
|
dbt.Fatalf("Error on %s %s: %s", method, query, err.Error())
|
|
}
|
|
|
|
func (dbt *DBTest) mustExec(query string, args ...interface{}) (res sql.Result) {
|
|
res, err := dbt.db.Exec(query, args...)
|
|
dbt.Assert(err, IsNil, Commentf("Exec %s", query))
|
|
return res
|
|
}
|
|
|
|
func (dbt *DBTest) mustQuery(query string, args ...interface{}) (rows *sql.Rows) {
|
|
rows, err := dbt.db.Query(query, args...)
|
|
dbt.Assert(err, IsNil, Commentf("Query %s", query))
|
|
return rows
|
|
}
|
|
|
|
func (dbt *DBTest) mustQueryRows(query string, args ...interface{}) {
|
|
rows := dbt.mustQuery(query, args...)
|
|
dbt.Assert(rows.Next(), IsTrue)
|
|
rows.Close()
|
|
}
|
|
|
|
func runTestRegression(c *C) {
|
|
runTests(c, dsn, func(dbt *DBTest) {
|
|
// Create Table
|
|
dbt.mustExec("CREATE TABLE test (val TINYINT)")
|
|
|
|
// Test for unexpected data
|
|
var out bool
|
|
rows := dbt.mustQuery("SELECT * FROM test")
|
|
dbt.Assert(rows.Next(), IsFalse, Commentf("unexpected data in empty table"))
|
|
|
|
// Create Data
|
|
res := dbt.mustExec("INSERT INTO test VALUES (1)")
|
|
// res := dbt.mustExec("INSERT INTO test VALUES (?)", 1)
|
|
count, err := res.RowsAffected()
|
|
dbt.Assert(err, IsNil)
|
|
dbt.Check(count, Equals, int64(1))
|
|
id, err := res.LastInsertId()
|
|
dbt.Assert(err, IsNil)
|
|
dbt.Check(id, Equals, int64(0))
|
|
|
|
// Read
|
|
rows = dbt.mustQuery("SELECT val FROM test")
|
|
if rows.Next() {
|
|
rows.Scan(&out)
|
|
dbt.Check(out, IsTrue)
|
|
dbt.Check(rows.Next(), IsFalse, Commentf("unexpected data"))
|
|
} else {
|
|
dbt.Error("no data")
|
|
}
|
|
rows.Close()
|
|
|
|
// Update
|
|
res = dbt.mustExec("UPDATE test SET val = 0 WHERE val = ?", 1)
|
|
count, err = res.RowsAffected()
|
|
dbt.Assert(err, IsNil)
|
|
dbt.Check(count, Equals, int64(1))
|
|
|
|
// Check Update
|
|
rows = dbt.mustQuery("SELECT val FROM test")
|
|
if rows.Next() {
|
|
rows.Scan(&out)
|
|
dbt.Check(out, IsFalse)
|
|
dbt.Check(rows.Next(), IsFalse, Commentf("unexpected data"))
|
|
} else {
|
|
dbt.Error("no data")
|
|
}
|
|
rows.Close()
|
|
|
|
// Delete
|
|
res = dbt.mustExec("DELETE FROM test WHERE val = 0")
|
|
// res = dbt.mustExec("DELETE FROM test WHERE val = ?", 0)
|
|
count, err = res.RowsAffected()
|
|
dbt.Assert(err, IsNil)
|
|
dbt.Check(count, Equals, int64(1))
|
|
|
|
// Check for unexpected rows
|
|
res = dbt.mustExec("DELETE FROM test")
|
|
count, err = res.RowsAffected()
|
|
dbt.Assert(err, IsNil)
|
|
dbt.Check(count, Equals, int64(0))
|
|
|
|
dbt.mustQueryRows("SELECT 1")
|
|
|
|
b := []byte{}
|
|
if err := dbt.db.QueryRow("SELECT ?", b).Scan(&b); err != nil {
|
|
dbt.Fatal(err)
|
|
}
|
|
if b == nil {
|
|
dbt.Error("nil echo from non-nil input")
|
|
}
|
|
})
|
|
}
|
|
|
|
func runTestPrepareResultFieldType(t *C) {
|
|
var param int64 = 83
|
|
runTests(t, dsn, func(dbt *DBTest) {
|
|
stmt, err := dbt.db.Prepare(`SELECT ?`)
|
|
if err != nil {
|
|
dbt.Fatal(err)
|
|
}
|
|
defer stmt.Close()
|
|
row := stmt.QueryRow(param)
|
|
var result int64
|
|
err = row.Scan(&result)
|
|
if err != nil {
|
|
dbt.Fatal(err)
|
|
}
|
|
switch {
|
|
case result != param:
|
|
dbt.Fatal("Unexpected result value")
|
|
}
|
|
})
|
|
}
|
|
|
|
func runTestSpecialType(t *C) {
|
|
runTests(t, dsn, func(dbt *DBTest) {
|
|
dbt.mustExec("create table test (a decimal(10, 5), b datetime, c time)")
|
|
dbt.mustExec("insert test values (1.4, '2012-12-21 12:12:12', '4:23:34')")
|
|
rows := dbt.mustQuery("select * from test where a > ?", 0)
|
|
t.Assert(rows.Next(), IsTrue)
|
|
var outA float64
|
|
var outB, outC string
|
|
err := rows.Scan(&outA, &outB, &outC)
|
|
t.Assert(err, IsNil)
|
|
t.Assert(outA, Equals, 1.4)
|
|
t.Assert(outB, Equals, "2012-12-21 12:12:12")
|
|
t.Assert(outC, Equals, "04:23:34")
|
|
})
|
|
}
|
|
|
|
func runTestPreparedString(t *C) {
|
|
runTests(t, dsn, func(dbt *DBTest) {
|
|
dbt.mustExec("create table test (a char(10), b char(10))")
|
|
dbt.mustExec("insert test values (?, ?)", "abcdeabcde", "abcde")
|
|
rows := dbt.mustQuery("select * from test where 1 = ?", 1)
|
|
t.Assert(rows.Next(), IsTrue)
|
|
var outA, outB string
|
|
err := rows.Scan(&outA, &outB)
|
|
t.Assert(err, IsNil)
|
|
t.Assert(outA, Equals, "abcdeabcde")
|
|
t.Assert(outB, Equals, "abcde")
|
|
})
|
|
}
|
|
|
|
func runTestConcurrentUpdate(c *C) {
|
|
runTests(c, dsn, func(dbt *DBTest) {
|
|
dbt.mustExec("create table test (a int, b int)")
|
|
dbt.mustExec("insert test values (1, 1)")
|
|
txn1, err := dbt.db.Begin()
|
|
c.Assert(err, IsNil)
|
|
|
|
txn2, err := dbt.db.Begin()
|
|
c.Assert(err, IsNil)
|
|
|
|
_, err = txn2.Exec("update test set a = a + 1 where b = 1")
|
|
c.Assert(err, IsNil)
|
|
err = txn2.Commit()
|
|
c.Assert(err, IsNil)
|
|
|
|
_, err = txn1.Exec("update test set a = a + 1 where b = 1")
|
|
c.Assert(err, IsNil)
|
|
|
|
err = txn1.Commit()
|
|
c.Assert(err, IsNil)
|
|
})
|
|
}
|
|
|
|
func runTestErrorCode(c *C) {
|
|
runTests(c, dsn, func(dbt *DBTest) {
|
|
dbt.mustExec("create table test (c int PRIMARY KEY);")
|
|
dbt.mustExec("insert into test values (1);")
|
|
txn1, err := dbt.db.Begin()
|
|
c.Assert(err, IsNil)
|
|
_, err = txn1.Exec("insert into test values(1)")
|
|
c.Assert(err, IsNil)
|
|
err = txn1.Commit()
|
|
checkErrorCode(c, err, tmysql.ErrDupEntry)
|
|
|
|
// Schema errors
|
|
txn2, err := dbt.db.Begin()
|
|
c.Assert(err, IsNil)
|
|
_, err = txn2.Exec("use db_not_exists;")
|
|
checkErrorCode(c, err, tmysql.ErrBadDB)
|
|
_, err = txn2.Exec("select * from tbl_not_exists;")
|
|
checkErrorCode(c, err, tmysql.ErrNoSuchTable)
|
|
_, err = txn2.Exec("create database test;")
|
|
checkErrorCode(c, err, tmysql.ErrDBCreateExists)
|
|
_, err = txn2.Exec("create database aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;")
|
|
checkErrorCode(c, err, tmysql.ErrTooLongIdent)
|
|
_, err = txn2.Exec("create table test (c int);")
|
|
checkErrorCode(c, err, tmysql.ErrTableExists)
|
|
_, err = txn2.Exec("drop table unknown_table;")
|
|
checkErrorCode(c, err, tmysql.ErrBadTable)
|
|
_, err = txn2.Exec("drop database unknown_db;")
|
|
checkErrorCode(c, err, tmysql.ErrDBDropExists)
|
|
_, err = txn2.Exec("create table aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa (a int);")
|
|
checkErrorCode(c, err, tmysql.ErrTooLongIdent)
|
|
_, err = txn2.Exec("create table long_column_table (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa int);")
|
|
checkErrorCode(c, err, tmysql.ErrTooLongIdent)
|
|
_, err = txn2.Exec("alter table test add aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa int;")
|
|
checkErrorCode(c, err, tmysql.ErrTooLongIdent)
|
|
|
|
// Optimizer errors
|
|
_, err = txn2.Exec("select *, * from test;")
|
|
checkErrorCode(c, err, tmysql.ErrParse)
|
|
_, err = txn2.Exec("select row(1, 2) > 1;")
|
|
checkErrorCode(c, err, tmysql.ErrOperandColumns)
|
|
_, err = txn2.Exec("select * from test order by row(c, c);")
|
|
checkErrorCode(c, err, tmysql.ErrOperandColumns)
|
|
|
|
// Variable errors
|
|
_, err = txn2.Exec("select @@unknown_sys_var;")
|
|
checkErrorCode(c, err, tmysql.ErrUnknownSystemVariable)
|
|
_, err = txn2.Exec("set @@unknown_sys_var='1';")
|
|
checkErrorCode(c, err, tmysql.ErrUnknownSystemVariable)
|
|
})
|
|
}
|
|
|
|
func checkErrorCode(c *C, e error, code uint16) {
|
|
me, ok := e.(*mysql.MySQLError)
|
|
c.Assert(ok, IsTrue)
|
|
c.Assert(me.Number, Equals, code)
|
|
}
|
|
|
|
func runTestAuth(c *C) {
|
|
runTests(c, dsn, func(dbt *DBTest) {
|
|
dbt.mustExec(`CREATE USER 'test'@'%' IDENTIFIED BY '123';`)
|
|
})
|
|
newDsn := "test:123@tcp(localhost:4001)/test?strict=true"
|
|
runTests(c, newDsn, func(dbt *DBTest) {
|
|
dbt.mustExec(`USE mysql;`)
|
|
})
|
|
|
|
db, err := sql.Open("mysql", "test:456@tcp(localhost:4001)/test?strict=true")
|
|
_, err = db.Query("USE mysql;")
|
|
c.Assert(err, NotNil, Commentf("Wrong password should be failed"))
|
|
db.Close()
|
|
}
|
|
|
|
func runTestIssues(c *C) {
|
|
// For issue #263
|
|
unExistsSchemaDsn := "root@tcp(localhost:4001)/unexists_schema?strict=true"
|
|
db, err := sql.Open("mysql", unExistsSchemaDsn)
|
|
c.Assert(db, NotNil)
|
|
c.Assert(err, IsNil)
|
|
// Open may just validate its arguments without creating a connection to the database. To verify that the data source name is valid, call Ping.
|
|
err = db.Ping()
|
|
c.Assert(err, NotNil, Commentf("Connecting to an unexists schema should be error"))
|
|
db.Close()
|
|
}
|
|
|
|
func runTestResultFieldTableIsNull(c *C) {
|
|
runTests(c, dsn, func(dbt *DBTest) {
|
|
dbt.mustExec("drop table if exists test;")
|
|
dbt.mustExec("create table test (c int);")
|
|
dbt.mustExec("explain select * from test;")
|
|
})
|
|
}
|
|
|
|
func runTestStatusAPI(c *C) {
|
|
resp, err := http.Get("http://127.0.0.1:10090/status")
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
decoder := json.NewDecoder(resp.Body)
|
|
var data status
|
|
err = decoder.Decode(&data)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(data.Version, Equals, tmysql.ServerVersion)
|
|
}
|
|
|
|
func runTestMultiPacket(c *C) {
|
|
runTests(c, dsn, func(dbt *DBTest) {
|
|
dbt.mustExec("set global max_allowed_packet=167772160") // 160M
|
|
})
|
|
|
|
runTests(c, dsn, func(dbt *DBTest) {
|
|
dbt.mustExec("create table test (a longtext)")
|
|
for i := 0; i < 100; i++ {
|
|
dbt.mustExec("insert into test values ('" + strings.Repeat("x", 1024*1024*16-i) + "')")
|
|
}
|
|
})
|
|
}
|