1003 lines
39 KiB
Go
1003 lines
39 KiB
Go
// Copyright 2022 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,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/pingcap/failpoint"
|
|
"github.com/pingcap/kvproto/pkg/coprocessor"
|
|
"github.com/pingcap/kvproto/pkg/kvrpcpb"
|
|
"github.com/pingcap/tidb/domain"
|
|
"github.com/pingcap/tidb/expression"
|
|
"github.com/pingcap/tidb/kv"
|
|
"github.com/pingcap/tidb/parser/ast"
|
|
"github.com/pingcap/tidb/parser/format"
|
|
"github.com/pingcap/tidb/parser/model"
|
|
"github.com/pingcap/tidb/parser/mysql"
|
|
"github.com/pingcap/tidb/parser/terror"
|
|
"github.com/pingcap/tidb/session"
|
|
"github.com/pingcap/tidb/store/mockstore"
|
|
"github.com/pingcap/tidb/testkit"
|
|
"github.com/pingcap/tidb/testkit/testutil"
|
|
"github.com/pingcap/tidb/types"
|
|
"github.com/pingcap/tidb/util"
|
|
"github.com/pingcap/tidb/util/sqlexec"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/tikv/client-go/v2/tikvrpc"
|
|
"github.com/tikv/client-go/v2/tikvrpc/interceptor"
|
|
)
|
|
|
|
func TestSchemaCheckerSQL(t *testing.T) {
|
|
store := testkit.CreateMockStoreWithSchemaLease(t, 1*time.Second)
|
|
|
|
setTxnTk := testkit.NewTestKit(t, store)
|
|
setTxnTk.MustExec("set global tidb_enable_metadata_lock=0")
|
|
setTxnTk.MustExec("set global tidb_txn_mode=''")
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk1 := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk1.MustExec("use test")
|
|
|
|
// create table
|
|
tk.MustExec(`create table t (id int, c int);`)
|
|
tk.MustExec(`create table t1 (id int, c int);`)
|
|
// insert data
|
|
tk.MustExec(`insert into t values(1, 1);`)
|
|
|
|
// The schema version is out of date in the first transaction, but the SQL can be retried.
|
|
tk.MustExec("set @@tidb_disable_txn_auto_retry = 0")
|
|
tk.MustExec(`begin;`)
|
|
tk1.MustExec(`alter table t add index idx(c);`)
|
|
tk.MustExec(`insert into t values(2, 2);`)
|
|
tk.MustExec(`commit;`)
|
|
|
|
// The schema version is out of date in the first transaction, and the SQL can't be retried.
|
|
atomic.StoreUint32(&session.SchemaChangedWithoutRetry, 1)
|
|
defer func() {
|
|
atomic.StoreUint32(&session.SchemaChangedWithoutRetry, 0)
|
|
}()
|
|
tk.MustExec(`begin;`)
|
|
tk1.MustExec(`alter table t modify column c bigint;`)
|
|
tk.MustExec(`insert into t values(3, 3);`)
|
|
err := tk.ExecToErr(`commit;`)
|
|
require.True(t, terror.ErrorEqual(err, domain.ErrInfoSchemaChanged), fmt.Sprintf("err %v", err))
|
|
|
|
// But the transaction related table IDs aren't in the updated table IDs.
|
|
tk.MustExec(`begin;`)
|
|
tk1.MustExec(`alter table t add index idx2(c);`)
|
|
tk.MustExec(`insert into t1 values(4, 4);`)
|
|
tk.MustExec(`commit;`)
|
|
|
|
// Test for "select for update".
|
|
tk.MustExec(`begin;`)
|
|
tk1.MustExec(`alter table t add index idx3(c);`)
|
|
tk.MustQuery(`select * from t for update`)
|
|
require.Error(t, tk.ExecToErr(`commit;`))
|
|
|
|
// Repeated tests for partitioned table
|
|
tk.MustExec(`create table pt (id int, c int) partition by hash (id) partitions 3`)
|
|
tk.MustExec(`insert into pt values(1, 1);`)
|
|
// The schema version is out of date in the first transaction, and the SQL can't be retried.
|
|
tk.MustExec(`begin;`)
|
|
tk1.MustExec(`alter table pt modify column c bigint;`)
|
|
tk.MustExec(`insert into pt values(3, 3);`)
|
|
err = tk.ExecToErr(`commit;`)
|
|
require.True(t, terror.ErrorEqual(err, domain.ErrInfoSchemaChanged), fmt.Sprintf("err %v", err))
|
|
|
|
// But the transaction related table IDs aren't in the updated table IDs.
|
|
tk.MustExec(`begin;`)
|
|
tk1.MustExec(`alter table pt add index idx2(c);`)
|
|
tk.MustExec(`insert into t1 values(4, 4);`)
|
|
tk.MustExec(`commit;`)
|
|
|
|
// Test for "select for update".
|
|
tk.MustExec(`begin;`)
|
|
tk1.MustExec(`alter table pt add index idx3(c);`)
|
|
tk.MustQuery(`select * from pt for update`)
|
|
require.Error(t, tk.ExecToErr(`commit;`))
|
|
|
|
// Test for "select for update".
|
|
tk.MustExec(`begin;`)
|
|
tk1.MustExec(`alter table pt add index idx4(c);`)
|
|
tk.MustQuery(`select * from pt partition (p1) for update`)
|
|
require.Error(t, tk.ExecToErr(`commit;`))
|
|
}
|
|
|
|
func TestLoadSchemaFailed(t *testing.T) {
|
|
originalRetryTime := domain.SchemaOutOfDateRetryTimes.Load()
|
|
originalRetryInterval := domain.SchemaOutOfDateRetryInterval.Load()
|
|
domain.SchemaOutOfDateRetryTimes.Store(3)
|
|
domain.SchemaOutOfDateRetryInterval.Store(20 * time.Millisecond)
|
|
defer func() {
|
|
domain.SchemaOutOfDateRetryTimes.Store(originalRetryTime)
|
|
domain.SchemaOutOfDateRetryInterval.Store(originalRetryInterval)
|
|
}()
|
|
|
|
store := testkit.CreateMockStoreWithSchemaLease(t, 1*time.Second)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk1 := testkit.NewTestKit(t, store)
|
|
tk2 := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk1.MustExec("use test")
|
|
tk2.MustExec("use test")
|
|
|
|
tk.MustExec("create table t (a int);")
|
|
tk.MustExec("create table t1 (a int);")
|
|
tk.MustExec("create table t2 (a int);")
|
|
|
|
tk1.MustExec("begin")
|
|
tk2.MustExec("begin")
|
|
|
|
// Make sure loading information schema is failed and server is invalid.
|
|
require.NoError(t, failpoint.Enable("github.com/pingcap/tidb/domain/ErrorMockReloadFailed", `return(true)`))
|
|
defer func() { require.NoError(t, failpoint.Disable("github.com/pingcap/tidb/domain/ErrorMockReloadFailed")) }()
|
|
require.Error(t, domain.GetDomain(tk.Session()).Reload())
|
|
|
|
lease := domain.GetDomain(tk.Session()).DDL().GetLease()
|
|
time.Sleep(lease * 2)
|
|
|
|
// Make sure executing insert statement is failed when server is invalid.
|
|
require.Error(t, tk.ExecToErr("insert t values (100);"))
|
|
|
|
tk1.MustExec("insert t1 values (100);")
|
|
tk2.MustExec("insert t2 values (100);")
|
|
|
|
require.Error(t, tk1.ExecToErr("commit"))
|
|
|
|
ver, err := store.CurrentVersion(kv.GlobalTxnScope)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, ver)
|
|
|
|
require.NoError(t, failpoint.Disable("github.com/pingcap/tidb/domain/ErrorMockReloadFailed"))
|
|
time.Sleep(lease * 2)
|
|
|
|
tk.MustExec("drop table if exists t;")
|
|
tk.MustExec("create table t (a int);")
|
|
tk.MustExec("insert t values (100);")
|
|
// Make sure insert to table t2 transaction executes.
|
|
tk2.MustExec("commit")
|
|
}
|
|
|
|
func TestWriteOnMultipleCachedTable(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk.MustExec("drop table if exists ct1, ct2")
|
|
tk.MustExec("create table ct1 (id int, c int)")
|
|
tk.MustExec("create table ct2 (id int, c int)")
|
|
tk.MustExec("alter table ct1 cache")
|
|
tk.MustExec("alter table ct2 cache")
|
|
tk.MustQuery("select * from ct1").Check(testkit.Rows())
|
|
tk.MustQuery("select * from ct2").Check(testkit.Rows())
|
|
|
|
lastReadFromCache := func(tk *testkit.TestKit) bool {
|
|
return tk.Session().GetSessionVars().StmtCtx.ReadFromTableCache
|
|
}
|
|
|
|
cached := false
|
|
for i := 0; i < 50; i++ {
|
|
tk.MustQuery("select * from ct1")
|
|
if lastReadFromCache(tk) {
|
|
cached = true
|
|
break
|
|
}
|
|
time.Sleep(100 * time.Millisecond)
|
|
}
|
|
require.True(t, cached)
|
|
|
|
tk.MustExec("begin")
|
|
tk.MustExec("insert into ct1 values (3, 4)")
|
|
tk.MustExec("insert into ct2 values (5, 6)")
|
|
tk.MustExec("commit")
|
|
|
|
tk.MustQuery("select * from ct1").Check(testkit.Rows("3 4"))
|
|
tk.MustQuery("select * from ct2").Check(testkit.Rows("5 6"))
|
|
|
|
// cleanup
|
|
tk.MustExec("alter table ct1 nocache")
|
|
tk.MustExec("alter table ct2 nocache")
|
|
}
|
|
|
|
func TestFixSetTiDBSnapshotTS(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
safePointName := "tikv_gc_safe_point"
|
|
safePointValue := "20160102-15:04:05 -0700"
|
|
safePointComment := "All versions after safe point can be accessed. (DO NOT EDIT)"
|
|
updateSafePoint := fmt.Sprintf(`INSERT INTO mysql.tidb VALUES ('%[1]s', '%[2]s', '%[3]s')
|
|
ON DUPLICATE KEY
|
|
UPDATE variable_value = '%[2]s', comment = '%[3]s'`, safePointName, safePointValue, safePointComment)
|
|
tk.MustExec(updateSafePoint)
|
|
tk.MustExec("create database t123")
|
|
time.Sleep(time.Second)
|
|
ts := time.Now().Format("2006-1-2 15:04:05")
|
|
time.Sleep(time.Second)
|
|
tk.MustExec("drop database t123")
|
|
tk.MustMatchErrMsg("use t123", ".*Unknown database.*")
|
|
tk.MustExec(fmt.Sprintf("set @@tidb_snapshot='%s'", ts))
|
|
tk.MustExec("use t123")
|
|
// update any session variable and assert whether infoschema is changed
|
|
tk.MustExec("SET SESSION sql_mode = 'STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER';")
|
|
tk.MustExec("use t123")
|
|
}
|
|
|
|
func TestPrepareZero(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk.MustExec("drop table if exists t")
|
|
tk.MustExec("create table t(v timestamp)")
|
|
tk.MustExec("prepare s1 from 'insert into t (v) values (?)'")
|
|
tk.MustExec("set @v1='0'")
|
|
require.Error(t, tk.ExecToErr("execute s1 using @v1"))
|
|
tk.MustExec("set @v2='" + types.ZeroDatetimeStr + "'")
|
|
tk.MustExec("set @orig_sql_mode=@@sql_mode; set @@sql_mode='';")
|
|
tk.MustExec("execute s1 using @v2")
|
|
tk.MustQuery("select v from t").Check(testkit.Rows("0000-00-00 00:00:00"))
|
|
tk.MustExec("set @@sql_mode=@orig_sql_mode;")
|
|
}
|
|
|
|
func TestPrimaryKeyAutoIncrement(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk.MustExec("drop table if exists t")
|
|
tk.MustExec("create table t (id BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL, name varchar(255) UNIQUE NOT NULL, status int)")
|
|
tk.MustExec("insert t (name) values (?)", "abc")
|
|
id := tk.Session().LastInsertID()
|
|
require.NotZero(t, id)
|
|
|
|
tk1 := testkit.NewTestKit(t, store)
|
|
tk1.MustExec("use test")
|
|
tk1.MustQuery("select * from t").Check(testkit.Rows(fmt.Sprintf("%d abc <nil>", id)))
|
|
|
|
tk.MustExec("update t set name = 'abc', status = 1 where id = ?", id)
|
|
tk1.MustQuery("select * from t").Check(testkit.Rows(fmt.Sprintf("%d abc 1", id)))
|
|
|
|
// Check for pass bool param to tidb prepared statement
|
|
tk.MustExec("drop table if exists t")
|
|
tk.MustExec("create table t (id tinyint)")
|
|
tk.MustExec("insert t values (?)", true)
|
|
tk.MustQuery("select * from t").Check(testkit.Rows("1"))
|
|
}
|
|
|
|
// TestTruncateAlloc tests that the auto_increment ID does not reuse the old table's allocator.
|
|
func TestTruncateAlloc(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk.MustExec("create table truncate_id (a int primary key auto_increment)")
|
|
tk.MustExec("insert truncate_id values (), (), (), (), (), (), (), (), (), ()")
|
|
tk.MustExec("truncate table truncate_id")
|
|
tk.MustExec("insert truncate_id values (), (), (), (), (), (), (), (), (), ()")
|
|
tk.MustQuery("select a from truncate_id where a > 11").Check(testkit.Rows())
|
|
}
|
|
|
|
func TestParseWithParams(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
tk := testkit.NewTestKit(t, store)
|
|
se := tk.Session()
|
|
exec := se.(sqlexec.RestrictedSQLExecutor)
|
|
|
|
// test compatibility with ExcuteInternal
|
|
_, err := exec.ParseWithParams(context.TODO(), "SELECT 4")
|
|
require.NoError(t, err)
|
|
|
|
// test charset attack
|
|
stmt, err := exec.ParseWithParams(context.TODO(), "SELECT * FROM test WHERE name = %? LIMIT 1", "\xbf\x27 OR 1=1 /*")
|
|
require.NoError(t, err)
|
|
|
|
var sb strings.Builder
|
|
ctx := format.NewRestoreCtx(format.RestoreStringDoubleQuotes, &sb)
|
|
err = stmt.Restore(ctx)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "SELECT * FROM test WHERE name=_utf8mb4\"\xbf' OR 1=1 /*\" LIMIT 1", sb.String())
|
|
|
|
// test invalid sql
|
|
_, err = exec.ParseWithParams(context.TODO(), "SELECT")
|
|
require.Regexp(t, ".*You have an error in your SQL syntax.*", err)
|
|
|
|
// test invalid arguments to escape
|
|
_, err = exec.ParseWithParams(context.TODO(), "SELECT %?, %?", 3)
|
|
require.Regexp(t, "missing arguments.*", err)
|
|
|
|
// test noescape
|
|
stmt, err = exec.ParseWithParams(context.TODO(), "SELECT 3")
|
|
require.NoError(t, err)
|
|
|
|
sb.Reset()
|
|
ctx = format.NewRestoreCtx(0, &sb)
|
|
err = stmt.Restore(ctx)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "SELECT 3", sb.String())
|
|
}
|
|
|
|
func TestDoDDLJobQuit(t *testing.T) {
|
|
// This is required since mock tikv does not support paging.
|
|
failpoint.Enable("github.com/pingcap/tidb/store/copr/DisablePaging", `return`)
|
|
defer func() {
|
|
require.NoError(t, failpoint.Disable("github.com/pingcap/tidb/store/copr/DisablePaging"))
|
|
}()
|
|
|
|
// test https://github.com/pingcap/tidb/issues/18714, imitate DM's use environment
|
|
// use isolated store, because in below failpoint we will cancel its context
|
|
store, err := mockstore.NewMockStore(mockstore.WithStoreType(mockstore.MockTiKV))
|
|
require.NoError(t, err)
|
|
defer func() { require.NoError(t, store.Close()) }()
|
|
dom, err := session.BootstrapSession(store)
|
|
require.NoError(t, err)
|
|
defer dom.Close()
|
|
se, err := session.CreateSession(store)
|
|
require.NoError(t, err)
|
|
defer se.Close()
|
|
|
|
require.Nil(t, failpoint.Enable("github.com/pingcap/tidb/ddl/storeCloseInLoop", `return`))
|
|
defer func() { require.NoError(t, failpoint.Disable("github.com/pingcap/tidb/ddl/storeCloseInLoop")) }()
|
|
|
|
// this DDL call will enter deadloop before this fix
|
|
err = dom.DDL().CreateSchema(se, &ast.CreateDatabaseStmt{Name: model.NewCIStr("testschema")})
|
|
require.Equal(t, "context canceled", err.Error())
|
|
}
|
|
|
|
func TestProcessInfoIssue22068(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk.MustExec("create table t(a int)")
|
|
var wg util.WaitGroupWrapper
|
|
wg.Run(func() {
|
|
tk.MustQuery("select 1 from t where a = (select sleep(5));").Check(testkit.Rows())
|
|
})
|
|
time.Sleep(2 * time.Second)
|
|
pi := tk.Session().ShowProcess()
|
|
require.NotNil(t, pi)
|
|
require.Equal(t, "select 1 from t where a = (select sleep(5));", pi.Info)
|
|
require.Nil(t, pi.Plan)
|
|
wg.Wait()
|
|
}
|
|
|
|
func TestIssue19127(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk.MustExec("drop table if exists issue19127")
|
|
tk.MustExec("create table issue19127 (c_int int, c_str varchar(40), primary key (c_int, c_str) ) partition by hash (c_int) partitions 4;")
|
|
tk.MustExec("insert into issue19127 values (9, 'angry williams'), (10, 'thirsty hugle');")
|
|
_, _ = tk.Exec("update issue19127 set c_int = c_int + 10, c_str = 'adoring stonebraker' where c_int in (10, 9);")
|
|
require.Equal(t, uint64(2), tk.Session().AffectedRows())
|
|
}
|
|
|
|
func TestPerStmtTaskID(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk.MustExec("create table task_id (v int)")
|
|
|
|
tk.MustExec("begin")
|
|
tk.MustExec("select * from task_id where v > 10")
|
|
taskID1 := tk.Session().GetSessionVars().StmtCtx.TaskID
|
|
tk.MustExec("select * from task_id where v < 5")
|
|
taskID2 := tk.Session().GetSessionVars().StmtCtx.TaskID
|
|
tk.MustExec("commit")
|
|
|
|
require.NotEqual(t, taskID1, taskID2)
|
|
}
|
|
|
|
func TestStmtHints(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
|
|
// Test MEMORY_QUOTA hint
|
|
tk.MustExec("select /*+ MEMORY_QUOTA(1 MB) */ 1;")
|
|
val := int64(1) * 1024 * 1024
|
|
require.True(t, tk.Session().GetSessionVars().MemTracker.CheckBytesLimit(val))
|
|
tk.MustExec("select /*+ MEMORY_QUOTA(1 GB) */ 1;")
|
|
val = int64(1) * 1024 * 1024 * 1024
|
|
require.True(t, tk.Session().GetSessionVars().MemTracker.CheckBytesLimit(val))
|
|
tk.MustExec("select /*+ MEMORY_QUOTA(1 GB), MEMORY_QUOTA(1 MB) */ 1;")
|
|
val = int64(1) * 1024 * 1024
|
|
require.Len(t, tk.Session().GetSessionVars().StmtCtx.GetWarnings(), 1)
|
|
require.True(t, tk.Session().GetSessionVars().MemTracker.CheckBytesLimit(val))
|
|
tk.MustExec("select /*+ MEMORY_QUOTA(0 GB) */ 1;")
|
|
val = int64(0)
|
|
require.Len(t, tk.Session().GetSessionVars().StmtCtx.GetWarnings(), 1)
|
|
require.True(t, tk.Session().GetSessionVars().MemTracker.CheckBytesLimit(val))
|
|
require.EqualError(t, tk.Session().GetSessionVars().StmtCtx.GetWarnings()[0].Err, "Setting the MEMORY_QUOTA to 0 means no memory limit")
|
|
|
|
tk.MustExec("use test")
|
|
tk.MustExec("create table t1(a int);")
|
|
tk.MustExec("insert /*+ MEMORY_QUOTA(1 MB) */ into t1 (a) values (1);")
|
|
val = int64(1) * 1024 * 1024
|
|
require.True(t, tk.Session().GetSessionVars().MemTracker.CheckBytesLimit(val))
|
|
|
|
tk.MustExec("insert /*+ MEMORY_QUOTA(1 MB) */ into t1 select /*+ MEMORY_QUOTA(3 MB) */ * from t1;")
|
|
val = int64(1) * 1024 * 1024
|
|
require.True(t, tk.Session().GetSessionVars().MemTracker.CheckBytesLimit(val))
|
|
require.Len(t, tk.Session().GetSessionVars().StmtCtx.GetWarnings(), 1)
|
|
require.EqualError(t, tk.Session().GetSessionVars().StmtCtx.GetWarnings()[0].Err, "[util:3126]Hint MEMORY_QUOTA(`3145728`) is ignored as conflicting/duplicated.")
|
|
|
|
// Test NO_INDEX_MERGE hint
|
|
tk.Session().GetSessionVars().SetEnableIndexMerge(true)
|
|
tk.MustExec("select /*+ NO_INDEX_MERGE() */ 1;")
|
|
require.True(t, tk.Session().GetSessionVars().StmtCtx.NoIndexMergeHint)
|
|
tk.MustExec("select /*+ NO_INDEX_MERGE(), NO_INDEX_MERGE() */ 1;")
|
|
require.Len(t, tk.Session().GetSessionVars().StmtCtx.GetWarnings(), 1)
|
|
require.True(t, tk.Session().GetSessionVars().GetEnableIndexMerge())
|
|
|
|
// Test STRAIGHT_JOIN hint
|
|
tk.MustExec("select /*+ straight_join() */ 1;")
|
|
require.True(t, tk.Session().GetSessionVars().StmtCtx.StraightJoinOrder)
|
|
tk.MustExec("select /*+ straight_join(), straight_join() */ 1;")
|
|
require.Len(t, tk.Session().GetSessionVars().StmtCtx.GetWarnings(), 1)
|
|
|
|
// Test USE_TOJA hint
|
|
tk.Session().GetSessionVars().SetAllowInSubqToJoinAndAgg(true)
|
|
tk.MustExec("select /*+ USE_TOJA(false) */ 1;")
|
|
require.False(t, tk.Session().GetSessionVars().GetAllowInSubqToJoinAndAgg())
|
|
tk.Session().GetSessionVars().SetAllowInSubqToJoinAndAgg(false)
|
|
tk.MustExec("select /*+ USE_TOJA(true) */ 1;")
|
|
require.True(t, tk.Session().GetSessionVars().GetAllowInSubqToJoinAndAgg())
|
|
tk.MustExec("select /*+ USE_TOJA(false), USE_TOJA(true) */ 1;")
|
|
require.Len(t, tk.Session().GetSessionVars().StmtCtx.GetWarnings(), 1)
|
|
require.True(t, tk.Session().GetSessionVars().GetAllowInSubqToJoinAndAgg())
|
|
|
|
// Test USE_CASCADES hint
|
|
tk.Session().GetSessionVars().SetEnableCascadesPlanner(true)
|
|
tk.MustExec("select /*+ USE_CASCADES(false) */ 1;")
|
|
require.False(t, tk.Session().GetSessionVars().GetEnableCascadesPlanner())
|
|
tk.Session().GetSessionVars().SetEnableCascadesPlanner(false)
|
|
tk.MustExec("select /*+ USE_CASCADES(true) */ 1;")
|
|
require.True(t, tk.Session().GetSessionVars().GetEnableCascadesPlanner())
|
|
tk.MustExec("select /*+ USE_CASCADES(false), USE_CASCADES(true) */ 1;")
|
|
require.Len(t, tk.Session().GetSessionVars().StmtCtx.GetWarnings(), 1)
|
|
require.EqualError(t, tk.Session().GetSessionVars().StmtCtx.GetWarnings()[0].Err, "USE_CASCADES() is defined more than once, only the last definition takes effect: USE_CASCADES(true)")
|
|
require.True(t, tk.Session().GetSessionVars().GetEnableCascadesPlanner())
|
|
|
|
// Test READ_CONSISTENT_REPLICA hint
|
|
tk.Session().GetSessionVars().SetReplicaRead(kv.ReplicaReadLeader)
|
|
tk.MustExec("select /*+ READ_CONSISTENT_REPLICA() */ 1;")
|
|
require.Equal(t, kv.ReplicaReadFollower, tk.Session().GetSessionVars().GetReplicaRead())
|
|
tk.MustExec("select /*+ READ_CONSISTENT_REPLICA(), READ_CONSISTENT_REPLICA() */ 1;")
|
|
require.Len(t, tk.Session().GetSessionVars().StmtCtx.GetWarnings(), 1)
|
|
require.Equal(t, kv.ReplicaReadFollower, tk.Session().GetSessionVars().GetReplicaRead())
|
|
}
|
|
|
|
func TestLoadClientInteractive(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.RefreshSession()
|
|
tk.Session().GetSessionVars().ClientCapability = tk.Session().GetSessionVars().ClientCapability | mysql.ClientInteractive
|
|
tk.MustQuery("select @@wait_timeout").Check(testkit.Rows("28800"))
|
|
}
|
|
|
|
func TestHostLengthMax(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
|
|
host1 := strings.Repeat("a", 65)
|
|
host2 := strings.Repeat("a", 256)
|
|
|
|
tk.MustExec(fmt.Sprintf(`CREATE USER 'abcddfjakldfjaldddds'@'%s'`, host1))
|
|
tk.MustGetErrMsg(fmt.Sprintf(`CREATE USER 'abcddfjakldfjaldddds'@'%s'`, host2), "[ddl:1470]String 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' is too long for host name (should be no longer than 255)")
|
|
}
|
|
|
|
func TestRollbackOnCompileError(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk.MustExec("create table t (a int)")
|
|
tk.MustExec("insert t values (1)")
|
|
|
|
tk2 := testkit.NewTestKit(t, store)
|
|
tk2.MustExec("use test")
|
|
tk2.MustQuery("select * from t").Check(testkit.Rows("1"))
|
|
|
|
tk.MustExec("rename table t to t2")
|
|
var meetErr bool
|
|
for i := 0; i < 100; i++ {
|
|
_, err := tk2.Exec("insert t values (1)")
|
|
if err != nil {
|
|
meetErr = true
|
|
break
|
|
}
|
|
}
|
|
require.True(t, meetErr)
|
|
|
|
tk.MustExec("rename table t2 to t")
|
|
var recoverErr bool
|
|
for i := 0; i < 100; i++ {
|
|
_, err := tk2.Exec("insert t values (1)")
|
|
if err == nil {
|
|
recoverErr = true
|
|
break
|
|
}
|
|
}
|
|
require.True(t, recoverErr)
|
|
}
|
|
|
|
func TestDeletePanic(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk.MustExec("create table t (c int)")
|
|
tk.MustExec("insert into t values (1), (2), (3)")
|
|
tk.MustExec("delete from `t` where `c` = ?", 1)
|
|
tk.MustExec("delete from `t` where `c` = ?", 2)
|
|
}
|
|
|
|
func TestSpecifyIndexPrefixLength(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
|
|
_, err := tk.Exec("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
|
|
require.Error(t, err)
|
|
|
|
_, err = tk.Exec("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
|
|
require.Error(t, err)
|
|
|
|
_, err = tk.Exec("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
|
|
require.Error(t, err)
|
|
|
|
tk.MustExec("create table t (c1 char, c2 int, c3 bit(10));")
|
|
|
|
_, err = tk.Exec("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
|
|
require.Error(t, err)
|
|
|
|
_, err = tk.Exec("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
|
|
require.Error(t, err)
|
|
|
|
_, err = tk.Exec("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
|
|
require.Error(t, err)
|
|
|
|
tk.MustExec("drop table if exists t;")
|
|
|
|
_, err = tk.Exec("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
|
|
require.Error(t, err)
|
|
|
|
tk.MustExec("create table t (c1 int, c2 blob, c3 varchar(64));")
|
|
_, err = tk.Exec("create index idx_c1 on t (c2);")
|
|
// ERROR 1170 (42000): BLOB/TEXT column 'c2' used in key specification without a key length
|
|
require.Error(t, err)
|
|
|
|
_, err = tk.Exec("create index idx_c1 on t (c2(555555));")
|
|
// ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
|
|
require.Error(t, err)
|
|
|
|
_, err = tk.Exec("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
|
|
require.Error(t, err)
|
|
|
|
tk.MustExec("create index idx_c1 on t (c1);")
|
|
tk.MustExec("create index idx_c2 on t (c2(3));")
|
|
tk.MustExec("create unique index idx_c3 on t (c3(5));")
|
|
|
|
tk.MustExec("insert into t values (3, 'abc', 'def');")
|
|
tk.MustQuery("select c2 from t where c2 = 'abc';").Check(testkit.Rows("abc"))
|
|
|
|
tk.MustExec("insert into t values (4, 'abcd', 'xxx');")
|
|
tk.MustExec("insert into t values (4, 'abcf', 'yyy');")
|
|
tk.MustQuery("select c2 from t where c2 = 'abcf';").Check(testkit.Rows("abcf"))
|
|
tk.MustQuery("select c2 from t where c2 = 'abcd';").Check(testkit.Rows("abcd"))
|
|
|
|
tk.MustExec("insert into t values (4, 'ignore', 'abcdeXXX');")
|
|
_, err = tk.Exec("insert into t values (5, 'ignore', 'abcdeYYY');")
|
|
// ERROR 1062 (23000): Duplicate entry 'abcde' for key 'idx_c3'
|
|
require.Error(t, err)
|
|
tk.MustQuery("select c3 from t where c3 = 'abcde';").Check(testkit.Rows())
|
|
|
|
tk.MustExec("delete from t where c3 = 'abcdeXXX';")
|
|
tk.MustExec("delete from t where c2 = 'abc';")
|
|
|
|
tk.MustQuery("select c2 from t where c2 > 'abcd';").Check(testkit.Rows("abcf"))
|
|
tk.MustQuery("select c2 from t where c2 < 'abcf';").Check(testkit.Rows("abcd"))
|
|
tk.MustQuery("select c2 from t where c2 >= 'abcd';").Check(testkit.Rows("abcd", "abcf"))
|
|
tk.MustQuery("select c2 from t where c2 <= 'abcf';").Check(testkit.Rows("abcd", "abcf"))
|
|
tk.MustQuery("select c2 from t where c2 != 'abc';").Check(testkit.Rows("abcd", "abcf"))
|
|
tk.MustQuery("select c2 from t where c2 != 'abcd';").Check(testkit.Rows("abcf"))
|
|
|
|
tk.MustExec("drop table if exists t1;")
|
|
tk.MustExec("create table t1 (a int, b char(255), key(a, b(20)));")
|
|
tk.MustExec("insert into t1 values (0, '1');")
|
|
tk.MustExec("update t1 set b = b + 1 where a = 0;")
|
|
tk.MustQuery("select b from t1 where a = 0;").Check(testkit.Rows("2"))
|
|
|
|
// test union index.
|
|
tk.MustExec("drop table if exists t;")
|
|
tk.MustExec("create table t (a text, b text, c int, index (a(3), b(3), c));")
|
|
tk.MustExec("insert into t values ('abc', 'abcd', 1);")
|
|
tk.MustExec("insert into t values ('abcx', 'abcf', 2);")
|
|
tk.MustExec("insert into t values ('abcy', 'abcf', 3);")
|
|
tk.MustExec("insert into t values ('bbc', 'abcd', 4);")
|
|
tk.MustExec("insert into t values ('bbcz', 'abcd', 5);")
|
|
tk.MustExec("insert into t values ('cbck', 'abd', 6);")
|
|
tk.MustQuery("select c from t where a = 'abc' and b <= 'abc';").Check(testkit.Rows())
|
|
tk.MustQuery("select c from t where a = 'abc' and b <= 'abd';").Check(testkit.Rows("1"))
|
|
tk.MustQuery("select c from t where a < 'cbc' and b > 'abcd';").Check(testkit.Rows("2", "3"))
|
|
tk.MustQuery("select c from t where a <= 'abd' and b > 'abc';").Check(testkit.Rows("1", "2", "3"))
|
|
tk.MustQuery("select c from t where a < 'bbcc' and b = 'abcd';").Check(testkit.Rows("1", "4"))
|
|
tk.MustQuery("select c from t where a > 'bbcf';").Check(testkit.Rows("5", "6"))
|
|
}
|
|
|
|
func TestResultField(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk.MustExec("create table t (id int);")
|
|
|
|
tk.MustExec(`INSERT INTO t VALUES (1);`)
|
|
tk.MustExec(`INSERT INTO t VALUES (2);`)
|
|
r, err := tk.Exec(`SELECT count(*) from t;`)
|
|
require.NoError(t, err)
|
|
defer r.Close()
|
|
fields := r.Fields()
|
|
require.NoError(t, err)
|
|
require.Len(t, fields, 1)
|
|
field := fields[0].Column
|
|
require.Equal(t, mysql.TypeLonglong, field.GetType())
|
|
require.Equal(t, 21, field.GetFlen())
|
|
}
|
|
|
|
// Testcase for https://github.com/pingcap/tidb/issues/325
|
|
func TestResultType(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
rs, err := tk.Exec(`select cast(null as char(30))`)
|
|
require.NoError(t, err)
|
|
req := rs.NewChunk(nil)
|
|
err = rs.Next(context.Background(), req)
|
|
require.NoError(t, err)
|
|
require.True(t, req.GetRow(0).IsNull(0))
|
|
require.Equal(t, mysql.TypeVarString, rs.Fields()[0].Column.FieldType.GetType())
|
|
}
|
|
|
|
func TestFieldText(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk.MustExec("create table t (a int)")
|
|
tests := []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))"},
|
|
{"select 1 /*!32301 +1 */;", "1 +1 "},
|
|
{"select /*!32301 1 +1 */;", "1 +1 "},
|
|
{"/*!32301 select 1 +1 */;", "1 +1 "},
|
|
{"select 1 + /*!32301 1 +1 */;", "1 + 1 +1 "},
|
|
{"select 1 /*!32301 + 1, 1 */;", "1 + 1"},
|
|
{"select /*!32301 1, 1 +1 */;", "1"},
|
|
{"select /*!32301 1 + 1, */ +1;", "1 + 1"},
|
|
}
|
|
for _, tt := range tests {
|
|
result, err := tk.Exec(tt.sql)
|
|
require.NoError(t, err)
|
|
require.Equal(t, tt.field, result.Fields()[0].ColumnAsName.O)
|
|
result.Close()
|
|
}
|
|
}
|
|
|
|
// TestRowLock . See http://dev.mysql.com/doc/refman/5.7/en/commit.html.
|
|
func TestRowLock(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
setTxnTk := testkit.NewTestKit(t, store)
|
|
setTxnTk.MustExec("set global tidb_txn_mode=''")
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk1 := testkit.NewTestKit(t, store)
|
|
tk1.MustExec("use test")
|
|
tk2 := testkit.NewTestKit(t, store)
|
|
tk2.MustExec("use test")
|
|
|
|
tk.MustExec("drop table if exists t")
|
|
txn, err := tk.Session().Txn(true)
|
|
require.True(t, kv.ErrInvalidTxn.Equal(err))
|
|
require.False(t, txn.Valid())
|
|
tk.MustExec("create table t (c1 int, c2 int, c3 int)")
|
|
tk.MustExec("insert t values (11, 2, 3)")
|
|
tk.MustExec("insert t values (12, 2, 3)")
|
|
tk.MustExec("insert t values (13, 2, 3)")
|
|
|
|
tk1.MustExec("set @@tidb_disable_txn_auto_retry = 0")
|
|
tk1.MustExec("begin")
|
|
tk1.MustExec("update t set c2=21 where c1=11")
|
|
|
|
tk2.MustExec("begin")
|
|
tk2.MustExec("update t set c2=211 where c1=11")
|
|
tk2.MustExec("commit")
|
|
|
|
// tk1 will retry and the final value is 21
|
|
tk1.MustExec("commit")
|
|
|
|
// Check the result is correct
|
|
tk.MustQuery("select c2 from t where c1=11").Check(testkit.Rows("21"))
|
|
|
|
tk1.MustExec("begin")
|
|
tk1.MustExec("update t set c2=21 where c1=11")
|
|
|
|
tk2.MustExec("begin")
|
|
tk2.MustExec("update t set c2=22 where c1=12")
|
|
tk2.MustExec("commit")
|
|
|
|
tk1.MustExec("commit")
|
|
}
|
|
|
|
func TestMatchIdentity(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk.MustExec("CREATE USER `useridentity`@`%`")
|
|
tk.MustExec("CREATE USER `useridentity`@`localhost`")
|
|
tk.MustExec("CREATE USER `useridentity`@`192.168.1.1`")
|
|
tk.MustExec("CREATE USER `useridentity`@`example.com`")
|
|
|
|
// The MySQL matching rule is most specific to least specific.
|
|
// So if I log in from 192.168.1.1 I should match that entry always.
|
|
identity, err := tk.Session().MatchIdentity("useridentity", "192.168.1.1")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "useridentity", identity.Username)
|
|
require.Equal(t, "192.168.1.1", identity.Hostname)
|
|
|
|
// If I log in from localhost, I should match localhost
|
|
identity, err = tk.Session().MatchIdentity("useridentity", "localhost")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "useridentity", identity.Username)
|
|
require.Equal(t, "localhost", identity.Hostname)
|
|
|
|
// If I log in from 192.168.1.2 I should match wildcard.
|
|
identity, err = tk.Session().MatchIdentity("useridentity", "192.168.1.2")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "useridentity", identity.Username)
|
|
require.Equal(t, "%", identity.Hostname)
|
|
|
|
identity, err = tk.Session().MatchIdentity("useridentity", "127.0.0.1")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "useridentity", identity.Username)
|
|
require.Equal(t, "localhost", identity.Hostname)
|
|
|
|
// This uses the lookup of example.com to get an IP address.
|
|
// We then login with that IP address, but expect it to match the example.com
|
|
// entry in the privileges table (by reverse lookup).
|
|
ips, err := net.LookupHost("example.com")
|
|
require.NoError(t, err)
|
|
identity, err = tk.Session().MatchIdentity("useridentity", ips[0])
|
|
require.NoError(t, err)
|
|
require.Equal(t, "useridentity", identity.Username)
|
|
// FIXME: we *should* match example.com instead
|
|
// as long as skip-name-resolve is not set (DEFAULT)
|
|
require.Equal(t, "%", identity.Hostname)
|
|
}
|
|
|
|
func TestLastInsertID(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
// insert
|
|
tk.MustExec("create table t (c1 int not null auto_increment, c2 int, PRIMARY KEY (c1))")
|
|
tk.MustExec("insert into t set c2 = 11")
|
|
tk.MustQuery("select last_insert_id()").Check(testkit.Rows("1"))
|
|
|
|
tk.MustExec("insert into t (c2) values (22), (33), (44)")
|
|
tk.MustQuery("select last_insert_id()").Check(testkit.Rows("2"))
|
|
|
|
tk.MustExec("insert into t (c1, c2) values (10, 55)")
|
|
tk.MustQuery("select last_insert_id()").Check(testkit.Rows("2"))
|
|
|
|
// replace
|
|
tk.MustExec("replace t (c2) values(66)")
|
|
tk.MustQuery("select * from t").Check(testkit.Rows("1 11", "2 22", "3 33", "4 44", "10 55", "11 66"))
|
|
tk.MustQuery("select last_insert_id()").Check(testkit.Rows("11"))
|
|
|
|
// update
|
|
tk.MustExec("update t set c1=last_insert_id(c1 + 100)")
|
|
tk.MustQuery("select * from t").Check(testkit.Rows("101 11", "102 22", "103 33", "104 44", "110 55", "111 66"))
|
|
tk.MustQuery("select last_insert_id()").Check(testkit.Rows("111"))
|
|
tk.MustExec("insert into t (c2) values (77)")
|
|
tk.MustQuery("select last_insert_id()").Check(testkit.Rows("112"))
|
|
|
|
// drop
|
|
tk.MustExec("drop table t")
|
|
tk.MustQuery("select last_insert_id()").Check(testkit.Rows("112"))
|
|
|
|
tk.MustExec("create table t (c2 int, c3 int, c1 int not null auto_increment, PRIMARY KEY (c1))")
|
|
tk.MustExec("insert into t set c2 = 30")
|
|
|
|
// insert values
|
|
lastInsertID := tk.Session().LastInsertID()
|
|
tk.MustExec("prepare stmt1 from 'insert into t (c2) values (?)'")
|
|
tk.MustExec("set @v1=10")
|
|
tk.MustExec("set @v2=20")
|
|
tk.MustExec("execute stmt1 using @v1")
|
|
tk.MustExec("execute stmt1 using @v2")
|
|
tk.MustExec("deallocate prepare stmt1")
|
|
currLastInsertID := tk.Session().GetSessionVars().StmtCtx.PrevLastInsertID
|
|
tk.MustQuery("select c1 from t where c2 = 20").Check(testkit.Rows(fmt.Sprint(currLastInsertID)))
|
|
require.Equal(t, currLastInsertID, lastInsertID+2)
|
|
}
|
|
|
|
func TestBinaryReadOnly(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
setTxnTk := testkit.NewTestKit(t, store)
|
|
setTxnTk.MustExec("set global tidb_txn_mode=''")
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk.MustExec("create table t (i int key)")
|
|
id, _, _, err := tk.Session().PrepareStmt("select i from t where i = ?")
|
|
require.NoError(t, err)
|
|
id2, _, _, err := tk.Session().PrepareStmt("insert into t values (?)")
|
|
require.NoError(t, err)
|
|
tk.MustExec("set autocommit = 0")
|
|
tk.MustExec("set tidb_disable_txn_auto_retry = 0")
|
|
_, err = tk.Session().ExecutePreparedStmt(context.Background(), id, expression.Args2Expressions4Test(1))
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0, session.GetHistory(tk.Session()).Count())
|
|
tk.MustExec("insert into t values (1)")
|
|
require.Equal(t, 1, session.GetHistory(tk.Session()).Count())
|
|
_, err = tk.Session().ExecutePreparedStmt(context.Background(), id2, expression.Args2Expressions4Test(2))
|
|
require.NoError(t, err)
|
|
require.Equal(t, 2, session.GetHistory(tk.Session()).Count())
|
|
tk.MustExec("commit")
|
|
}
|
|
|
|
func TestHandleAssertionFailureForPartitionedTable(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
tk := testkit.NewTestKit(t, store)
|
|
se := tk.Session()
|
|
se.SetConnectionID(1)
|
|
tk.MustExec("use test")
|
|
tk.MustExec("create table t (a int, b int, c int, primary key(a, b)) partition by range (a) (partition p0 values less than (10), partition p1 values less than (20))")
|
|
failpoint.Enable("github.com/pingcap/tidb/table/tables/addRecordForceAssertExist", "return")
|
|
defer failpoint.Disable("github.com/pingcap/tidb/table/tables/addRecordForceAssertExist")
|
|
|
|
ctx, hook := testutil.WithLogHook(context.TODO(), t, "table")
|
|
_, err := tk.ExecWithContext(ctx, "insert into t values (1, 1, 1)")
|
|
require.ErrorContains(t, err, "assertion")
|
|
hook.CheckLogCount(t, 0)
|
|
}
|
|
|
|
func TestRandomBinary(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
|
|
ctx := kv.WithInternalSourceType(context.Background(), kv.InternalTxnStats)
|
|
allBytes := [][]byte{
|
|
{4, 0, 0, 0, 0, 0, 0, 4, '2'},
|
|
{4, 0, 0, 0, 0, 0, 0, 4, '.'},
|
|
{4, 0, 0, 0, 0, 0, 0, 4, '*'},
|
|
{4, 0, 0, 0, 0, 0, 0, 4, '('},
|
|
{4, 0, 0, 0, 0, 0, 0, 4, '\''},
|
|
{4, 0, 0, 0, 0, 0, 0, 4, '!'},
|
|
{4, 0, 0, 0, 0, 0, 0, 4, 29},
|
|
{4, 0, 0, 0, 0, 0, 0, 4, 28},
|
|
{4, 0, 0, 0, 0, 0, 0, 4, 23},
|
|
{4, 0, 0, 0, 0, 0, 0, 4, 16},
|
|
}
|
|
sql := "insert into mysql.stats_top_n (table_id, is_index, hist_id, value, count) values "
|
|
var val string
|
|
for i, bytes := range allBytes {
|
|
if i == 0 {
|
|
val += sqlexec.MustEscapeSQL("(874, 0, 1, %?, 3)", bytes)
|
|
} else {
|
|
val += sqlexec.MustEscapeSQL(",(874, 0, 1, %?, 3)", bytes)
|
|
}
|
|
}
|
|
sql += val
|
|
tk.MustExec("set sql_mode = 'NO_BACKSLASH_ESCAPES';")
|
|
_, err := tk.Session().ExecuteInternal(ctx, sql)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestSQLModeOp(t *testing.T) {
|
|
s := mysql.ModeNoBackslashEscapes | mysql.ModeOnlyFullGroupBy
|
|
d := mysql.DelSQLMode(s, mysql.ModeANSIQuotes)
|
|
require.Equal(t, s, d)
|
|
|
|
d = mysql.DelSQLMode(s, mysql.ModeNoBackslashEscapes)
|
|
require.Equal(t, mysql.ModeOnlyFullGroupBy, d)
|
|
|
|
s = mysql.ModeNoBackslashEscapes | mysql.ModeOnlyFullGroupBy
|
|
a := mysql.SetSQLMode(s, mysql.ModeOnlyFullGroupBy)
|
|
require.Equal(t, s, a)
|
|
|
|
a = mysql.SetSQLMode(s, mysql.ModeAllowInvalidDates)
|
|
require.Equal(t, mysql.ModeNoBackslashEscapes|mysql.ModeOnlyFullGroupBy|mysql.ModeAllowInvalidDates, a)
|
|
}
|
|
|
|
func TestRequestSource(t *testing.T) {
|
|
store := testkit.CreateMockStore(t, mockstore.WithStoreType(mockstore.MockTiKV))
|
|
tk := testkit.NewTestKit(t, store)
|
|
withCheckInterceptor := func(source string) interceptor.RPCInterceptor {
|
|
return interceptor.NewRPCInterceptor("kv-request-source-verify", func(next interceptor.RPCInterceptorFunc) interceptor.RPCInterceptorFunc {
|
|
return func(target string, req *tikvrpc.Request) (*tikvrpc.Response, error) {
|
|
requestSource := ""
|
|
readType := ""
|
|
switch r := req.Req.(type) {
|
|
case *kvrpcpb.PrewriteRequest:
|
|
requestSource = r.GetContext().GetRequestSource()
|
|
case *kvrpcpb.CommitRequest:
|
|
requestSource = r.GetContext().GetRequestSource()
|
|
case *coprocessor.Request:
|
|
readType = "-leader" // read request will be attached with read type
|
|
requestSource = r.GetContext().GetRequestSource()
|
|
case *kvrpcpb.GetRequest:
|
|
readType = "-leader" // read request will be attached with read type
|
|
requestSource = r.GetContext().GetRequestSource()
|
|
case *kvrpcpb.BatchGetRequest:
|
|
readType = "-leader" // read request will be attached with read type
|
|
requestSource = r.GetContext().GetRequestSource()
|
|
}
|
|
require.Equal(t, source+readType, requestSource)
|
|
return next(target, req)
|
|
}
|
|
})
|
|
}
|
|
ctx := context.Background()
|
|
tk.MustExecWithContext(ctx, "use test")
|
|
tk.MustExecWithContext(ctx, "create table t(a int primary key, b int)")
|
|
tk.MustExecWithContext(ctx, "set @@tidb_request_source_type = 'lightning'")
|
|
tk.MustQueryWithContext(ctx, "select @@tidb_request_source_type").Check(testkit.Rows("lightning"))
|
|
insertCtx := interceptor.WithRPCInterceptor(context.Background(), withCheckInterceptor("external_Insert_lightning"))
|
|
tk.MustExecWithContext(insertCtx, "insert into t values(1, 1)")
|
|
selectCtx := interceptor.WithRPCInterceptor(context.Background(), withCheckInterceptor("external_Select_lightning"))
|
|
tk.MustExecWithContext(selectCtx, "select count(*) from t;")
|
|
tk.MustQueryWithContext(selectCtx, "select b from t where a = 1;")
|
|
tk.MustQueryWithContext(selectCtx, "select b from t where a in (1, 2, 3);")
|
|
}
|