551 lines
19 KiB
Go
551 lines
19 KiB
Go
// Copyright 2016 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 writetest
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"testing"
|
|
|
|
"github.com/pingcap/tidb/br/pkg/lightning/mydump"
|
|
"github.com/pingcap/tidb/pkg/errctx"
|
|
"github.com/pingcap/tidb/pkg/executor"
|
|
"github.com/pingcap/tidb/pkg/kv"
|
|
"github.com/pingcap/tidb/pkg/parser/model"
|
|
"github.com/pingcap/tidb/pkg/parser/mysql"
|
|
"github.com/pingcap/tidb/pkg/session"
|
|
"github.com/pingcap/tidb/pkg/sessionctx"
|
|
"github.com/pingcap/tidb/pkg/sessiontxn"
|
|
"github.com/pingcap/tidb/pkg/store/mockstore"
|
|
"github.com/pingcap/tidb/pkg/table/tables"
|
|
"github.com/pingcap/tidb/pkg/testkit"
|
|
"github.com/pingcap/tidb/pkg/types"
|
|
"github.com/pingcap/tidb/pkg/util"
|
|
"github.com/pingcap/tidb/pkg/util/mock"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestInsertIgnore(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
var cfg kv.InjectionConfig
|
|
tk := testkit.NewTestKit(t, kv.NewInjectedStore(store, &cfg))
|
|
tk.MustExec("use test")
|
|
testSQL := `drop table if exists t;
|
|
create table t (id int PRIMARY KEY AUTO_INCREMENT, c1 int unique key);`
|
|
tk.MustExec(testSQL)
|
|
testSQL = `insert into t values (1, 2);`
|
|
tk.MustExec(testSQL)
|
|
require.Empty(t, tk.Session().LastMessage())
|
|
|
|
r := tk.MustQuery("select * from t;")
|
|
rowStr := fmt.Sprintf("%v %v", "1", "2")
|
|
r.Check(testkit.Rows(rowStr))
|
|
|
|
tk.MustExec("insert ignore into t values (1, 3), (2, 3)")
|
|
require.Equal(t, tk.Session().LastMessage(), "Records: 2 Duplicates: 1 Warnings: 1")
|
|
r = tk.MustQuery("select * from t;")
|
|
rowStr1 := fmt.Sprintf("%v %v", "2", "3")
|
|
r.Check(testkit.Rows(rowStr, rowStr1))
|
|
|
|
tk.MustExec("insert ignore into t values (3, 4), (3, 4)")
|
|
require.Equal(t, tk.Session().LastMessage(), "Records: 2 Duplicates: 1 Warnings: 1")
|
|
r = tk.MustQuery("select * from t;")
|
|
rowStr2 := fmt.Sprintf("%v %v", "3", "4")
|
|
r.Check(testkit.Rows(rowStr, rowStr1, rowStr2))
|
|
|
|
tk.MustExec("begin")
|
|
tk.MustExec("insert ignore into t values (4, 4), (4, 5), (4, 6)")
|
|
require.Equal(t, tk.Session().LastMessage(), "Records: 3 Duplicates: 2 Warnings: 2")
|
|
r = tk.MustQuery("select * from t;")
|
|
rowStr3 := fmt.Sprintf("%v %v", "4", "5")
|
|
r.Check(testkit.Rows(rowStr, rowStr1, rowStr2, rowStr3))
|
|
tk.MustExec("commit")
|
|
|
|
cfg.SetGetError(errors.New("foo"))
|
|
err := tk.ExecToErr("insert ignore into t values (1, 3)")
|
|
require.Error(t, err)
|
|
cfg.SetGetError(nil)
|
|
|
|
// for issue 4268
|
|
testSQL = `drop table if exists t;
|
|
create table t (a bigint);`
|
|
tk.MustExec(testSQL)
|
|
testSQL = "insert ignore into t select '1a';"
|
|
err = tk.ExecToErr(testSQL)
|
|
require.NoError(t, err)
|
|
require.Equal(t, tk.Session().LastMessage(), "Records: 1 Duplicates: 0 Warnings: 1")
|
|
r = tk.MustQuery("SHOW WARNINGS")
|
|
r.Check(testkit.Rows("Warning 1292 Truncated incorrect DOUBLE value: '1a'"))
|
|
testSQL = "insert ignore into t values ('1a')"
|
|
err = tk.ExecToErr(testSQL)
|
|
require.NoError(t, err)
|
|
require.Empty(t, tk.Session().LastMessage())
|
|
r = tk.MustQuery("SHOW WARNINGS")
|
|
// TODO: MySQL8.0 reports Warning 1265 Data truncated for column 'a' at row 1
|
|
r.Check(testkit.Rows("Warning 1366 Incorrect bigint value: '1a' for column 'a' at row 1"))
|
|
|
|
// for duplicates with warning
|
|
testSQL = `drop table if exists t;
|
|
create table t(a int primary key, b int);`
|
|
tk.MustExec(testSQL)
|
|
testSQL = "insert ignore into t values (1,1);"
|
|
tk.MustExec(testSQL)
|
|
require.Empty(t, tk.Session().LastMessage())
|
|
err = tk.ExecToErr(testSQL)
|
|
require.Empty(t, tk.Session().LastMessage())
|
|
require.NoError(t, err)
|
|
r = tk.MustQuery("SHOW WARNINGS")
|
|
r.Check(testkit.Rows("Warning 1062 Duplicate entry '1' for key 't.PRIMARY'"))
|
|
|
|
testSQL = `drop table if exists test;
|
|
create table test (i int primary key, j int unique);
|
|
begin;
|
|
insert into test values (1,1);
|
|
insert ignore into test values (2,1);
|
|
commit;`
|
|
tk.MustExec(testSQL)
|
|
testSQL = `select * from test;`
|
|
r = tk.MustQuery(testSQL)
|
|
r.Check(testkit.Rows("1 1"))
|
|
|
|
testSQL = `delete from test;
|
|
insert into test values (1, 1);
|
|
begin;
|
|
delete from test where i = 1;
|
|
insert ignore into test values (2, 1);
|
|
commit;`
|
|
tk.MustExec(testSQL)
|
|
testSQL = `select * from test;`
|
|
r = tk.MustQuery(testSQL)
|
|
r.Check(testkit.Rows("2 1"))
|
|
|
|
testSQL = `delete from test;
|
|
insert into test values (1, 1);
|
|
begin;
|
|
update test set i = 2, j = 2 where i = 1;
|
|
insert ignore into test values (1, 3);
|
|
insert ignore into test values (2, 4);
|
|
commit;`
|
|
tk.MustExec(testSQL)
|
|
testSQL = `select * from test order by i;`
|
|
r = tk.MustQuery(testSQL)
|
|
r.Check(testkit.Rows("1 3", "2 2"))
|
|
|
|
testSQL = `create table badnull (i int not null)`
|
|
tk.MustExec(testSQL)
|
|
testSQL = `insert ignore into badnull values (null)`
|
|
tk.MustExec(testSQL)
|
|
require.Empty(t, tk.Session().LastMessage())
|
|
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1048 Column 'i' cannot be null"))
|
|
testSQL = `select * from badnull`
|
|
tk.MustQuery(testSQL).Check(testkit.Rows("0"))
|
|
|
|
tk.MustExec("create table tp (id int) partition by range (id) (partition p0 values less than (1), partition p1 values less than(2))")
|
|
tk.MustExec("insert ignore into tp values (1), (3)")
|
|
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1526 Table has no partition for value 3"))
|
|
}
|
|
|
|
type testCase struct {
|
|
data []byte
|
|
expected []string
|
|
expectedMsg string
|
|
}
|
|
|
|
func checkCases(
|
|
tests []testCase,
|
|
loadSQL string,
|
|
t *testing.T,
|
|
tk *testkit.TestKit,
|
|
ctx sessionctx.Context,
|
|
selectSQL, deleteSQL string,
|
|
) {
|
|
for _, tt := range tests {
|
|
var reader io.ReadCloser = mydump.NewStringReader(string(tt.data))
|
|
var readerBuilder executor.LoadDataReaderBuilder = func(_ string) (
|
|
r io.ReadCloser, err error,
|
|
) {
|
|
return reader, nil
|
|
}
|
|
|
|
ctx.SetValue(executor.LoadDataReaderBuilderKey, readerBuilder)
|
|
tk.MustExec(loadSQL)
|
|
warnings := tk.Session().GetSessionVars().StmtCtx.GetWarnings()
|
|
for _, w := range warnings {
|
|
fmt.Printf("warnnig: %#v\n", w.Err.Error())
|
|
}
|
|
require.Equal(t, tt.expectedMsg, tk.Session().LastMessage(), tt.expected)
|
|
tk.MustQuery(selectSQL).Check(testkit.RowsWithSep("|", tt.expected...))
|
|
tk.MustExec(deleteSQL)
|
|
}
|
|
}
|
|
|
|
func TestLoadDataMissingColumn(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
createSQL := `create table load_data_missing (id int, t timestamp not null)`
|
|
tk.MustExec(createSQL)
|
|
loadSQL := "load data local infile '/tmp/nonexistence.csv' ignore into table load_data_missing"
|
|
ctx := tk.Session().(sessionctx.Context)
|
|
|
|
deleteSQL := "delete from load_data_missing"
|
|
selectSQL := "select id, hour(t), minute(t) from load_data_missing;"
|
|
|
|
curTime := types.CurrentTime(mysql.TypeTimestamp)
|
|
timeHour := curTime.Hour()
|
|
timeMinute := curTime.Minute()
|
|
tests := []testCase{
|
|
{[]byte(""), nil, "Records: 0 Deleted: 0 Skipped: 0 Warnings: 0"},
|
|
{[]byte("12\n"), []string{fmt.Sprintf("12|%v|%v", timeHour, timeMinute)}, "Records: 1 Deleted: 0 Skipped: 0 Warnings: 1"},
|
|
}
|
|
checkCases(tests, loadSQL, t, tk, ctx, selectSQL, deleteSQL)
|
|
|
|
tk.MustExec("alter table load_data_missing add column t2 timestamp null")
|
|
curTime = types.CurrentTime(mysql.TypeTimestamp)
|
|
timeHour = curTime.Hour()
|
|
timeMinute = curTime.Minute()
|
|
selectSQL = "select id, hour(t), minute(t), t2 from load_data_missing;"
|
|
tests = []testCase{
|
|
{[]byte("12\n"), []string{fmt.Sprintf("12|%v|%v|<nil>", timeHour, timeMinute)}, "Records: 1 Deleted: 0 Skipped: 0 Warnings: 1"},
|
|
}
|
|
checkCases(tests, loadSQL, t, tk, ctx, selectSQL, deleteSQL)
|
|
}
|
|
|
|
func TestIssue18681(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
createSQL := `drop table if exists load_data_test;
|
|
create table load_data_test (a bit(1),b bit(1),c bit(1),d bit(1));`
|
|
tk.MustExec(createSQL)
|
|
loadSQL := "load data local infile '/tmp/nonexistence.csv' ignore into table load_data_test"
|
|
ctx := tk.Session().(sessionctx.Context)
|
|
|
|
deleteSQL := "delete from load_data_test"
|
|
selectSQL := "select bin(a), bin(b), bin(c), bin(d) from load_data_test;"
|
|
levels := ctx.GetSessionVars().StmtCtx.ErrLevels()
|
|
levels[errctx.ErrGroupDupKey] = errctx.LevelWarn
|
|
levels[errctx.ErrGroupBadNull] = errctx.LevelWarn
|
|
|
|
sc := ctx.GetSessionVars().StmtCtx
|
|
oldTypeFlags := sc.TypeFlags()
|
|
defer func() {
|
|
sc.SetTypeFlags(oldTypeFlags)
|
|
}()
|
|
sc.SetTypeFlags(oldTypeFlags.WithIgnoreTruncateErr(true))
|
|
tests := []testCase{
|
|
{[]byte("true\tfalse\t0\t1\n"), []string{"1|0|0|1"}, "Records: 1 Deleted: 0 Skipped: 0 Warnings: 0"},
|
|
}
|
|
checkCases(tests, loadSQL, t, tk, ctx, selectSQL, deleteSQL)
|
|
require.Equal(t, uint16(0), sc.WarningCount())
|
|
}
|
|
|
|
func TestIssue34358(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
tk := testkit.NewTestKit(t, store)
|
|
ctx := tk.Session().(sessionctx.Context)
|
|
defer ctx.SetValue(executor.LoadDataVarKey, nil)
|
|
|
|
tk.MustExec("use test")
|
|
tk.MustExec("drop table if exists load_data_test")
|
|
tk.MustExec("create table load_data_test (a varchar(10), b varchar(10))")
|
|
|
|
loadSQL := "load data local infile '/tmp/nonexistence.csv' into table load_data_test ( @v1, " +
|
|
"@v2 ) set a = @v1, b = @v2"
|
|
checkCases([]testCase{
|
|
{[]byte("\\N\n"), []string{"<nil>|<nil>"}, "Records: 1 Deleted: 0 Skipped: 0 Warnings: 1"},
|
|
}, loadSQL, t, tk, ctx, "select * from load_data_test", "delete from load_data_test",
|
|
)
|
|
}
|
|
|
|
func TestLatch(t *testing.T) {
|
|
store, err := mockstore.NewMockStore(
|
|
// Small latch slot size to make conflicts.
|
|
mockstore.WithTxnLocalLatches(64),
|
|
)
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
err := store.Close()
|
|
require.NoError(t, err)
|
|
}()
|
|
|
|
dom, err1 := session.BootstrapSession(store)
|
|
require.Nil(t, err1)
|
|
defer dom.Close()
|
|
|
|
setTxnTk := testkit.NewTestKit(t, store)
|
|
setTxnTk.MustExec("set global tidb_txn_mode=''")
|
|
tk1 := testkit.NewTestKit(t, store)
|
|
tk1.MustExec("use test")
|
|
tk1.MustExec("drop table if exists t")
|
|
tk1.MustExec("create table t (id int)")
|
|
tk1.MustExec("set @@tidb_disable_txn_auto_retry = true")
|
|
|
|
tk2 := testkit.NewTestKit(t, store)
|
|
tk2.MustExec("use test")
|
|
tk1.MustExec("set @@tidb_disable_txn_auto_retry = true")
|
|
|
|
fn := func() {
|
|
tk1.MustExec("begin")
|
|
for i := 0; i < 100; i++ {
|
|
tk1.MustExec(fmt.Sprintf("insert into t values (%d)", i))
|
|
}
|
|
tk2.MustExec("begin")
|
|
for i := 100; i < 200; i++ {
|
|
tk1.MustExec(fmt.Sprintf("insert into t values (%d)", i))
|
|
}
|
|
tk2.MustExec("commit")
|
|
}
|
|
|
|
// txn1 and txn2 data range do not overlap, using latches should not
|
|
// result in txn conflict.
|
|
fn()
|
|
tk1.MustExec("commit")
|
|
|
|
tk1.MustExec("truncate table t")
|
|
fn()
|
|
tk1.MustExec("commit")
|
|
|
|
// Test the error type of latch and it could be retry if TiDB enable the retry.
|
|
tk1.MustExec("begin")
|
|
tk1.MustExec("update t set id = id + 1")
|
|
tk2.MustExec("update t set id = id + 1")
|
|
tk1.MustGetDBError("commit", kv.ErrWriteConflictInTiDB)
|
|
}
|
|
|
|
func TestReplaceLog(t *testing.T) {
|
|
store, domain := testkit.CreateMockStoreAndDomain(t)
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk.MustExec(`create table testLog (a int not null primary key, b int unique key);`)
|
|
|
|
// Make some dangling index.
|
|
ctx := mock.NewContext()
|
|
ctx.Store = store
|
|
is := domain.InfoSchema()
|
|
dbName := model.NewCIStr("test")
|
|
tblName := model.NewCIStr("testLog")
|
|
tbl, err := is.TableByName(dbName, tblName)
|
|
require.NoError(t, err)
|
|
tblInfo := tbl.Meta()
|
|
idxInfo := tblInfo.FindIndexByName("b")
|
|
indexOpr := tables.NewIndex(tblInfo.ID, tblInfo, idxInfo)
|
|
|
|
txn, err := store.Begin()
|
|
require.NoError(t, err)
|
|
_, err = indexOpr.Create(ctx, txn, types.MakeDatums(1), kv.IntHandle(1), nil)
|
|
require.NoError(t, err)
|
|
err = txn.Commit(context.Background())
|
|
require.NoError(t, err)
|
|
|
|
err = tk.ExecToErr(`replace into testLog values (0, 0), (1, 1);`)
|
|
require.Error(t, err)
|
|
require.EqualError(t, err, `can not be duplicated row, due to old row not found. handle 1 not found`)
|
|
tk.MustQuery(`admin cleanup index testLog b;`).Check(testkit.Rows("1"))
|
|
}
|
|
|
|
// TestRebaseIfNeeded is for issue 7422.
|
|
// There is no need to do the rebase when updating a record if the auto-increment ID not changed.
|
|
// This could make the auto ID increasing speed slower.
|
|
func TestRebaseIfNeeded(t *testing.T) {
|
|
store, domain := testkit.CreateMockStoreAndDomain(t)
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
tk.MustExec(`create table t (a int not null primary key auto_increment, b int unique key);`)
|
|
tk.MustExec(`insert into t (b) values (1);`)
|
|
|
|
ctx := mock.NewContext()
|
|
ctx.Store = store
|
|
tbl, err := domain.InfoSchema().TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
|
|
require.NoError(t, err)
|
|
require.Nil(t, sessiontxn.NewTxn(context.Background(), ctx))
|
|
// AddRecord directly here will skip to rebase the auto ID in the insert statement,
|
|
// which could simulate another TiDB adds a large auto ID.
|
|
_, err = tbl.AddRecord(ctx, types.MakeDatums(30001, 2))
|
|
require.NoError(t, err)
|
|
txn, err := ctx.Txn(true)
|
|
require.NoError(t, err)
|
|
require.NoError(t, txn.Commit(context.Background()))
|
|
|
|
tk.MustExec(`update t set b = 3 where a = 30001;`)
|
|
tk.MustExec(`insert into t (b) values (4);`)
|
|
tk.MustQuery(`select a from t where b = 4;`).Check(testkit.Rows("2"))
|
|
|
|
tk.MustExec(`insert into t set b = 3 on duplicate key update a = a;`)
|
|
tk.MustExec(`insert into t (b) values (5);`)
|
|
tk.MustQuery(`select a from t where b = 5;`).Check(testkit.Rows("4"))
|
|
|
|
tk.MustExec(`insert into t set b = 3 on duplicate key update a = a + 1;`)
|
|
tk.MustExec(`insert into t (b) values (6);`)
|
|
tk.MustQuery(`select a from t where b = 6;`).Check(testkit.Rows("30003"))
|
|
}
|
|
|
|
func TestDeferConstraintCheckForInsert(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(`drop table if exists t;create table t (a int primary key, b int);`)
|
|
tk.MustExec(`insert into t values (1,2),(2,2)`)
|
|
err := tk.ExecToErr("update t set a=a+1 where b=2")
|
|
require.Error(t, err)
|
|
|
|
tk.MustExec(`drop table if exists t;create table t (i int key);`)
|
|
tk.MustExec(`insert t values (1);`)
|
|
tk.MustExec(`set tidb_constraint_check_in_place = 1;`)
|
|
tk.MustExec(`begin;`)
|
|
err = tk.ExecToErr(`insert t values (1);`)
|
|
require.Error(t, err)
|
|
tk.MustExec(`update t set i = 2 where i = 1;`)
|
|
tk.MustExec(`commit;`)
|
|
tk.MustQuery(`select * from t;`).Check(testkit.Rows("2"))
|
|
|
|
tk.MustExec(`set tidb_constraint_check_in_place = 0;`)
|
|
tk.MustExec("replace into t values (1),(2)")
|
|
tk.MustExec("begin")
|
|
err = tk.ExecToErr("update t set i = 2 where i = 1")
|
|
require.Error(t, err)
|
|
err = tk.ExecToErr("insert into t values (1) on duplicate key update i = i + 1")
|
|
require.Error(t, err)
|
|
tk.MustExec("rollback")
|
|
|
|
tk.MustExec(`drop table t; create table t (id int primary key, v int unique);`)
|
|
tk.MustExec(`insert into t values (1, 1)`)
|
|
tk.MustExec(`set tidb_constraint_check_in_place = 1;`)
|
|
tk.MustExec(`set @@autocommit = 0;`)
|
|
|
|
err = tk.ExecToErr("insert into t values (3, 1)")
|
|
require.Error(t, err)
|
|
err = tk.ExecToErr("insert into t values (1, 3)")
|
|
require.Error(t, err)
|
|
tk.MustExec("commit")
|
|
|
|
tk.MustExec(`set tidb_constraint_check_in_place = 0;`)
|
|
tk.MustExec("insert into t values (3, 1)")
|
|
tk.MustExec("insert into t values (1, 3)")
|
|
err = tk.ExecToErr("commit")
|
|
require.Error(t, err)
|
|
|
|
// Cover the temporary table.
|
|
for val := range []int{0, 1} {
|
|
tk.MustExec("set tidb_constraint_check_in_place = ?", val)
|
|
|
|
tk.MustExec("drop table t")
|
|
tk.MustExec("create global temporary table t (a int primary key, b int) on commit delete rows")
|
|
tk.MustExec("begin")
|
|
tk.MustExec("insert into t values (1, 1)")
|
|
err = tk.ExecToErr(`insert into t values (1, 3)`)
|
|
require.Error(t, err)
|
|
tk.MustExec("insert into t values (2, 2)")
|
|
err = tk.ExecToErr("update t set a = a + 1 where a = 1")
|
|
require.Error(t, err)
|
|
err = tk.ExecToErr("insert into t values (1, 3) on duplicated key update a = a + 1")
|
|
require.Error(t, err)
|
|
tk.MustExec("commit")
|
|
|
|
tk.MustExec("drop table t")
|
|
tk.MustExec("create global temporary table t (a int, b int unique) on commit delete rows")
|
|
tk.MustExec("begin")
|
|
tk.MustExec("insert into t values (1, 1)")
|
|
err = tk.ExecToErr(`insert into t values (3, 1)`)
|
|
require.Error(t, err)
|
|
tk.MustExec("insert into t values (2, 2)")
|
|
err = tk.ExecToErr("update t set b = b + 1 where a = 1")
|
|
require.Error(t, err)
|
|
err = tk.ExecToErr("insert into t values (3, 1) on duplicated key update b = b + 1")
|
|
require.Error(t, err)
|
|
tk.MustExec("commit")
|
|
|
|
// cases for temporary table
|
|
tk.MustExec("drop table if exists tl")
|
|
tk.MustExec("create temporary table tl (a int primary key, b int)")
|
|
tk.MustExec("begin")
|
|
tk.MustExec("insert into tl values (1, 1)")
|
|
err = tk.ExecToErr(`insert into tl values (1, 3)`)
|
|
require.Error(t, err)
|
|
tk.MustExec("insert into tl values (2, 2)")
|
|
err = tk.ExecToErr("update tl set a = a + 1 where a = 1")
|
|
require.Error(t, err)
|
|
err = tk.ExecToErr("insert into tl values (1, 3) on duplicated key update a = a + 1")
|
|
require.Error(t, err)
|
|
tk.MustExec("commit")
|
|
|
|
tk.MustExec("begin")
|
|
tk.MustQuery("select * from tl").Check(testkit.Rows("1 1", "2 2"))
|
|
err = tk.ExecToErr(`insert into tl values (1, 3)`)
|
|
require.Error(t, err)
|
|
err = tk.ExecToErr("update tl set a = a + 1 where a = 1")
|
|
require.Error(t, err)
|
|
err = tk.ExecToErr("insert into tl values (1, 3) on duplicated key update a = a + 1")
|
|
require.Error(t, err)
|
|
tk.MustExec("rollback")
|
|
|
|
tk.MustExec("drop table tl")
|
|
tk.MustExec("create temporary table tl (a int, b int unique)")
|
|
tk.MustExec("begin")
|
|
tk.MustExec("insert into tl values (1, 1)")
|
|
err = tk.ExecToErr(`insert into tl values (3, 1)`)
|
|
require.Error(t, err)
|
|
tk.MustExec("insert into tl values (2, 2)")
|
|
err = tk.ExecToErr("update tl set b = b + 1 where a = 1")
|
|
require.Error(t, err)
|
|
err = tk.ExecToErr("insert into tl values (3, 1) on duplicated key update b = b + 1")
|
|
require.Error(t, err)
|
|
tk.MustExec("commit")
|
|
|
|
tk.MustExec("begin")
|
|
tk.MustQuery("select * from tl").Check(testkit.Rows("1 1", "2 2"))
|
|
err = tk.ExecToErr(`insert into tl values (3, 1)`)
|
|
require.Error(t, err)
|
|
err = tk.ExecToErr("update tl set b = b + 1 where a = 1")
|
|
require.Error(t, err)
|
|
err = tk.ExecToErr("insert into tl values (3, 1) on duplicated key update b = b + 1")
|
|
require.Error(t, err)
|
|
tk.MustExec("rollback")
|
|
}
|
|
}
|
|
|
|
func TestPessimisticDeleteYourWrites(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
|
|
session1 := testkit.NewTestKit(t, store)
|
|
session1.MustExec("use test")
|
|
session2 := testkit.NewTestKit(t, store)
|
|
session2.MustExec("use test")
|
|
|
|
session1.MustExec("drop table if exists x;")
|
|
session1.MustExec("create table x (id int primary key, c int);")
|
|
|
|
session1.MustExec("set tidb_txn_mode = 'pessimistic'")
|
|
session2.MustExec("set tidb_txn_mode = 'pessimistic'")
|
|
|
|
session1.MustExec("begin;")
|
|
session1.MustExec("insert into x select 1, 1")
|
|
session1.MustExec("delete from x where id = 1")
|
|
session2.MustExec("begin;")
|
|
var wg util.WaitGroupWrapper
|
|
wg.Run(func() {
|
|
session2.MustExec("insert into x select 1, 2")
|
|
})
|
|
session1.MustExec("commit;")
|
|
wg.Wait()
|
|
session2.MustExec("commit;")
|
|
session2.MustQuery("select * from x").Check(testkit.Rows("1 2"))
|
|
}
|