Files
tidb/session/temporarytabletest/temporary_table_test.go
2023-02-14 14:30:01 +08:00

1007 lines
43 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 temporarytabletest
import (
"fmt"
"sort"
"strconv"
"strings"
"sync/atomic"
"testing"
"time"
"github.com/pingcap/tidb/domain"
"github.com/pingcap/tidb/errno"
"github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/parser/terror"
"github.com/pingcap/tidb/session"
"github.com/pingcap/tidb/sessionctx/variable"
"github.com/pingcap/tidb/testkit"
"github.com/stretchr/testify/require"
)
func TestLocalTemporaryTableInsert(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create temporary table tmp1 (id int primary key auto_increment, u int unique, v int)")
tk.MustExec("insert into tmp1 (u, v) values(11, 101)")
tk.MustExec("insert into tmp1 (u, v) values(12, 102)")
tk.MustExec("insert into tmp1 values(3, 13, 102)")
checkRecordOneTwoThreeAndNonExist := func() {
tk.MustQuery("select * from tmp1 where id=1").Check(testkit.Rows("1 11 101"))
tk.MustQuery("select * from tmp1 where id=2").Check(testkit.Rows("2 12 102"))
tk.MustQuery("select * from tmp1 where id=3").Check(testkit.Rows("3 13 102"))
tk.MustQuery("select * from tmp1 where id=99").Check(testkit.Rows())
}
// inserted records exist
checkRecordOneTwoThreeAndNonExist()
// insert dup records out txn must be error
require.True(t, kv.ErrKeyExists.Equal(tk.ExecToErr("insert into tmp1 values(1, 999, 9999)")))
checkRecordOneTwoThreeAndNonExist()
require.True(t, kv.ErrKeyExists.Equal(tk.ExecToErr("insert into tmp1 values(99, 11, 999)")))
checkRecordOneTwoThreeAndNonExist()
// insert dup records in txn must be error
tk.MustExec("begin")
require.True(t, kv.ErrKeyExists.Equal(tk.ExecToErr("insert into tmp1 values(1, 999, 9999)")))
checkRecordOneTwoThreeAndNonExist()
require.True(t, kv.ErrKeyExists.Equal(tk.ExecToErr("insert into tmp1 values(99, 11, 9999)")))
checkRecordOneTwoThreeAndNonExist()
tk.MustExec("insert into tmp1 values(4, 14, 104)")
tk.MustQuery("select * from tmp1 where id=4").Check(testkit.Rows("4 14 104"))
require.True(t, kv.ErrKeyExists.Equal(tk.ExecToErr("insert into tmp1 values(4, 999, 9999)")))
require.True(t, kv.ErrKeyExists.Equal(tk.ExecToErr("insert into tmp1 values(99, 14, 9999)")))
checkRecordOneTwoThreeAndNonExist()
tk.MustExec("commit")
// check committed insert works
checkRecordOneTwoThreeAndNonExist()
tk.MustQuery("select * from tmp1 where id=4").Check(testkit.Rows("4 14 104"))
// check rollback works
tk.MustExec("begin")
tk.MustExec("insert into tmp1 values(5, 15, 105)")
tk.MustQuery("select * from tmp1 where id=5").Check(testkit.Rows("5 15 105"))
tk.MustExec("rollback")
tk.MustQuery("select * from tmp1 where id=5").Check(testkit.Rows())
}
func TestLocalTemporaryTableUpdate(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create temporary table tmp1 (id int primary key, u int unique, v int)")
idList := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
insertRecords := func(idList []int) {
for _, id := range idList {
tk.MustExec("insert into tmp1 values (?, ?, ?)", id, id+100, id+1000)
}
}
checkNoChange := func() {
expect := make([]string, 0)
for _, id := range idList {
expect = append(expect, fmt.Sprintf("%d %d %d", id, id+100, id+1000))
}
tk.MustQuery("select * from tmp1").Check(testkit.Rows(expect...))
}
checkUpdatesAndDeletes := func(updates []string, deletes []int) {
modifyMap := make(map[int]string)
for _, m := range updates {
parts := strings.Split(strings.TrimSpace(m), " ")
require.NotZero(t, len(parts))
id, err := strconv.Atoi(parts[0])
require.NoError(t, err)
modifyMap[id] = m
}
for _, d := range deletes {
modifyMap[d] = ""
}
expect := make([]string, 0)
for _, id := range idList {
modify, exist := modifyMap[id]
if !exist {
expect = append(expect, fmt.Sprintf("%d %d %d", id, id+100, id+1000))
continue
}
if modify != "" {
expect = append(expect, modify)
}
delete(modifyMap, id)
}
otherIds := make([]int, 0)
for id := range modifyMap {
otherIds = append(otherIds, id)
}
sort.Ints(otherIds)
for _, id := range otherIds {
modify, exist := modifyMap[id]
require.True(t, exist)
expect = append(expect, modify)
}
tk.MustQuery("select * from tmp1").Check(testkit.Rows(expect...))
}
type checkSuccess struct {
update []string
delete []int
}
type checkError struct {
err error
}
cases := []struct {
sql string
checkResult interface{}
additionalCheck func(error)
}{
// update with point get for primary key
{"update tmp1 set v=999 where id=1", checkSuccess{[]string{"1 101 999"}, nil}, nil},
{"update tmp1 set id=12 where id=1", checkSuccess{[]string{"12 101 1001"}, []int{1}}, nil},
{"update tmp1 set id=1 where id=1", checkSuccess{nil, nil}, nil},
{"update tmp1 set u=101 where id=1", checkSuccess{nil, nil}, nil},
{"update tmp1 set v=999 where id=100", checkSuccess{nil, nil}, nil},
{"update tmp1 set u=102 where id=100", checkSuccess{nil, nil}, nil},
{"update tmp1 set u=21 where id=1", checkSuccess{[]string{"1 21 1001"}, nil}, func(_ error) {
// check index deleted
tk.MustQuery("select /*+ use_index(tmp1, u) */ * from tmp1 where u=101").Check(testkit.Rows())
tk.MustQuery("show warnings").Check(testkit.Rows())
}},
{"update tmp1 set id=2 where id=1", checkError{kv.ErrKeyExists}, nil},
{"update tmp1 set u=102 where id=1", checkError{kv.ErrKeyExists}, nil},
// update with batch point get for primary key
{"update tmp1 set v=v+1000 where id in (1, 3, 5)", checkSuccess{[]string{"1 101 2001", "3 103 2003", "5 105 2005"}, nil}, nil},
{"update tmp1 set u=u+1 where id in (9, 100)", checkSuccess{[]string{"9 110 1009"}, nil}, nil},
{"update tmp1 set u=101 where id in (100, 101)", checkSuccess{nil, nil}, nil},
{"update tmp1 set id=id+1 where id in (8, 9)", checkError{kv.ErrKeyExists}, nil},
{"update tmp1 set u=u+1 where id in (8, 9)", checkError{kv.ErrKeyExists}, nil},
{"update tmp1 set id=id+20 where id in (1, 3, 5)", checkSuccess{[]string{"21 101 1001", "23 103 1003", "25 105 1005"}, []int{1, 3, 5}}, nil},
{"update tmp1 set u=u+100 where id in (1, 3, 5)", checkSuccess{[]string{"1 201 1001", "3 203 1003", "5 205 1005"}, nil}, func(_ error) {
// check index deleted
tk.MustQuery("select /*+ use_index(tmp1, u) */ * from tmp1 where u in (101, 103, 105)").Check(testkit.Rows())
tk.MustQuery("show warnings").Check(testkit.Rows())
}},
// update with point get for unique key
{"update tmp1 set v=888 where u=101", checkSuccess{[]string{"1 101 888"}, nil}, nil},
{"update tmp1 set id=21 where u=101", checkSuccess{[]string{"21 101 1001"}, []int{1}}, nil},
{"update tmp1 set v=888 where u=201", checkSuccess{nil, nil}, nil},
{"update tmp1 set u=201 where u=101", checkSuccess{[]string{"1 201 1001"}, nil}, nil},
{"update tmp1 set id=2 where u=101", checkError{kv.ErrKeyExists}, nil},
{"update tmp1 set u=102 where u=101", checkError{kv.ErrKeyExists}, nil},
// update with batch point get for unique key
{"update tmp1 set v=v+1000 where u in (101, 103)", checkSuccess{[]string{"1 101 2001", "3 103 2003"}, nil}, nil},
{"update tmp1 set v=v+1000 where u in (201, 203)", checkSuccess{nil, nil}, nil},
{"update tmp1 set v=v+1000 where u in (101, 110)", checkSuccess{[]string{"1 101 2001"}, nil}, nil},
{"update tmp1 set id=id+1 where u in (108, 109)", checkError{kv.ErrKeyExists}, nil},
// update with table scan and index scan
{"update tmp1 set v=v+1000 where id<3", checkSuccess{[]string{"1 101 2001", "2 102 2002"}, nil}, nil},
{"update /*+ use_index(tmp1, u) */ tmp1 set v=v+1000 where u>107", checkSuccess{[]string{"8 108 2008", "9 109 2009"}, nil}, nil},
{"update tmp1 set v=v+1000 where v>=1007 or v<=1002", checkSuccess{[]string{"1 101 2001", "2 102 2002", "7 107 2007", "8 108 2008", "9 109 2009"}, nil}, nil},
{"update tmp1 set v=v+1000 where id>=10", checkSuccess{nil, nil}, nil},
{"update tmp1 set id=id+1 where id>7", checkError{kv.ErrKeyExists}, nil},
{"update tmp1 set id=id+1 where id>8", checkSuccess{[]string{"10 109 1009"}, []int{9}}, nil},
{"update tmp1 set u=u+1 where u>107", checkError{kv.ErrKeyExists}, nil},
{"update tmp1 set u=u+1 where u>108", checkSuccess{[]string{"9 110 1009"}, nil}, nil},
{"update /*+ use_index(tmp1, u) */ tmp1 set v=v+1000 where u>108 or u<102", checkSuccess{[]string{"1 101 2001", "9 109 2009"}, nil}, nil},
}
executeSQL := func(sql string, checkResult interface{}, additionalCheck func(error)) (err error) {
switch check := checkResult.(type) {
case checkSuccess:
tk.MustExec(sql)
tk.MustQuery("show warnings").Check(testkit.Rows())
checkUpdatesAndDeletes(check.update, check.delete)
case checkError:
err = tk.ExecToErr(sql)
require.Error(t, err)
expectedErr, _ := check.err.(*terror.Error)
require.True(t, expectedErr.Equal(err))
checkNoChange()
default:
t.Fail()
}
if additionalCheck != nil {
additionalCheck(err)
}
return
}
for _, sqlCase := range cases {
// update records in txn and records are inserted in txn
tk.MustExec("begin")
insertRecords(idList)
_ = executeSQL(sqlCase.sql, sqlCase.checkResult, sqlCase.additionalCheck)
tk.MustExec("rollback")
tk.MustQuery("select * from tmp1").Check(testkit.Rows())
// update records out of txn
insertRecords(idList)
_ = executeSQL(sqlCase.sql, sqlCase.checkResult, sqlCase.additionalCheck)
tk.MustExec("delete from tmp1")
// update records in txn and rollback
insertRecords(idList)
tk.MustExec("begin")
_ = executeSQL(sqlCase.sql, sqlCase.checkResult, sqlCase.additionalCheck)
tk.MustExec("rollback")
// rollback left records unmodified
checkNoChange()
// update records in txn and commit
tk.MustExec("begin")
err := executeSQL(sqlCase.sql, sqlCase.checkResult, sqlCase.additionalCheck)
tk.MustExec("commit")
if err != nil {
checkNoChange()
} else {
r, _ := sqlCase.checkResult.(checkSuccess)
checkUpdatesAndDeletes(r.update, r.delete)
}
if sqlCase.additionalCheck != nil {
sqlCase.additionalCheck(err)
}
tk.MustExec("delete from tmp1")
tk.MustQuery("select * from tmp1").Check(testkit.Rows())
}
}
func TestTemporaryTableSize(t *testing.T) {
// Test the @@tidb_tmp_table_max_size system variable.
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create global temporary table t (c1 int, c2 mediumtext) on commit delete rows")
tk.MustExec("create temporary table tl (c1 int, c2 mediumtext)")
tk.MustQuery("select @@global.tidb_tmp_table_max_size").Check(testkit.Rows(strconv.Itoa(variable.DefTiDBTmpTableMaxSize)))
require.Equal(t, int64(variable.DefTiDBTmpTableMaxSize), tk.Session().GetSessionVars().TMPTableSize)
// Min value 1M, so the result is change to 1M, with a warning.
tk.MustExec("set @@global.tidb_tmp_table_max_size = 123")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1292 Truncated incorrect tidb_tmp_table_max_size value: '123'"))
// Change the session scope value to 2M.
tk.MustExec("set @@session.tidb_tmp_table_max_size = 2097152")
require.Equal(t, int64(2097152), tk.Session().GetSessionVars().TMPTableSize)
// Check in another session, change session scope value does not affect the global scope.
tk1 := testkit.NewTestKit(t, store)
tk1.MustQuery("select @@global.tidb_tmp_table_max_size").Check(testkit.Rows(strconv.Itoa(1 << 20)))
// The value is now 1M, check the error when table size exceed it.
tk.MustExec(fmt.Sprintf("set @@session.tidb_tmp_table_max_size = %d", 1<<20))
tk.MustExec("begin")
tk.MustExec("insert into t values (1, repeat('x', 512*1024))")
tk.MustExec("insert into t values (1, repeat('x', 512*1024))")
tk.MustGetErrCode("insert into t values (1, repeat('x', 512*1024))", errno.ErrRecordFileFull)
tk.MustExec("rollback")
// Check local temporary table
tk.MustExec("begin")
tk.MustExec("insert into tl values (1, repeat('x', 512*1024))")
tk.MustExec("insert into tl values (1, repeat('x', 512*1024))")
tk.MustGetErrCode("insert into tl values (1, repeat('x', 512*1024))", errno.ErrRecordFileFull)
tk.MustExec("rollback")
// Check local temporary table with some data in session
tk.MustExec("insert into tl values (1, repeat('x', 512*1024))")
tk.MustExec("begin")
tk.MustExec("insert into tl values (1, repeat('x', 512*1024))")
tk.MustGetErrCode("insert into tl values (1, repeat('x', 512*1024))", errno.ErrRecordFileFull)
tk.MustExec("rollback")
}
func TestGlobalTemporaryTable(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create global temporary table g_tmp (a int primary key, b int, c int, index i_b(b)) on commit delete rows")
tk.MustExec("begin")
tk.MustExec("insert into g_tmp values (3, 3, 3)")
tk.MustExec("insert into g_tmp values (4, 7, 9)")
// Cover table scan.
tk.MustQuery("select * from g_tmp").Check(testkit.Rows("3 3 3", "4 7 9"))
// Cover index reader.
tk.MustQuery("select b from g_tmp where b > 3").Check(testkit.Rows("7"))
// Cover index lookup.
tk.MustQuery("select c from g_tmp where b = 3").Check(testkit.Rows("3"))
// Cover point get.
tk.MustQuery("select * from g_tmp where a = 3").Check(testkit.Rows("3 3 3"))
// Cover batch point get.
tk.MustQuery("select * from g_tmp where a in (2,3,4)").Check(testkit.Rows("3 3 3", "4 7 9"))
tk.MustExec("commit")
// The global temporary table data is discard after the transaction commit.
tk.MustQuery("select * from g_tmp").Check(testkit.Rows())
}
func TestRetryGlobalTemporaryTable(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 normal_table")
tk.MustExec("create table normal_table(a int primary key, b int)")
defer tk.MustExec("drop table if exists normal_table")
tk.MustExec("drop table if exists temp_table")
tk.MustExec("create global temporary table temp_table(a int primary key, b int) on commit delete rows")
defer tk.MustExec("drop table if exists temp_table")
// insert select
tk.MustExec("set tidb_disable_txn_auto_retry = 0")
tk.MustExec("insert normal_table value(100, 100)")
tk.MustExec("set @@autocommit = 0")
// used to make conflicts
tk.MustExec("update normal_table set b=b+1 where a=100")
tk.MustExec("insert temp_table value(1, 1)")
tk.MustExec("insert normal_table select * from temp_table")
require.Equal(t, 3, session.GetHistory(tk.Session()).Count())
// try to conflict with tk
tk1 := testkit.NewTestKit(t, store)
tk1.MustExec("use test")
tk1.MustExec("update normal_table set b=b+1 where a=100")
// It will retry internally.
tk.MustExec("commit")
tk.MustQuery("select a, b from normal_table order by a").Check(testkit.Rows("1 1", "100 102"))
tk.MustQuery("select a, b from temp_table order by a").Check(testkit.Rows())
// update multi-tables
tk.MustExec("update normal_table set b=b+1 where a=100")
tk.MustExec("insert temp_table value(1, 2)")
// before update: normal_table=(1 1) (100 102), temp_table=(1 2)
tk.MustExec("update normal_table, temp_table set normal_table.b=temp_table.b where normal_table.a=temp_table.a")
require.Equal(t, 3, session.GetHistory(tk.Session()).Count())
// try to conflict with tk
tk1.MustExec("update normal_table set b=b+1 where a=100")
// It will retry internally.
tk.MustExec("commit")
tk.MustQuery("select a, b from normal_table order by a").Check(testkit.Rows("1 2", "100 104"))
}
func TestRetryLocalTemporaryTable(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 normal_table")
tk.MustExec("create table normal_table(a int primary key, b int)")
defer tk.MustExec("drop table if exists normal_table")
tk.MustExec("drop table if exists temp_table")
tk.MustExec("create temporary table l_temp_table(a int primary key, b int)")
defer tk.MustExec("drop table if exists l_temp_table")
// insert select
tk.MustExec("set tidb_disable_txn_auto_retry = 0")
tk.MustExec("insert normal_table value(100, 100)")
tk.MustExec("set @@autocommit = 0")
// used to make conflicts
tk.MustExec("update normal_table set b=b+1 where a=100")
tk.MustExec("insert l_temp_table value(1, 2)")
tk.MustExec("insert normal_table select * from l_temp_table")
require.Equal(t, 3, session.GetHistory(tk.Session()).Count())
// try to conflict with tk
tk1 := testkit.NewTestKit(t, store)
tk1.MustExec("use test")
tk1.MustExec("update normal_table set b=b+1 where a=100")
// It will retry internally.
tk.MustExec("commit")
tk.MustQuery("select a, b from normal_table order by a").Check(testkit.Rows("1 2", "100 102"))
tk.MustQuery("select a, b from l_temp_table order by a").Check(testkit.Rows("1 2"))
// update multi-tables
tk.MustExec("update normal_table set b=b+1 where a=100")
tk.MustExec("insert l_temp_table value(3, 4)")
// before update: normal_table=(1 1) (100 102), temp_table=(1 2)
tk.MustExec("update normal_table, l_temp_table set normal_table.b=l_temp_table.b where normal_table.a=l_temp_table.a")
require.Equal(t, 3, session.GetHistory(tk.Session()).Count())
// try to conflict with tk
tk1.MustExec("update normal_table set b=b+1 where a=100")
// It will retry internally.
tk.MustExec("commit")
tk.MustQuery("select a, b from normal_table order by a").Check(testkit.Rows("1 2", "100 104"))
}
func TestLocalTemporaryTableInsertOnDuplicateKeyUpdate(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create temporary table tmp1 (id int primary key auto_increment, u int unique, v int)")
tk.MustExec("insert into tmp1 values(1, 11, 101)")
tk.MustExec("insert into tmp1 values(2, 12, 102)")
// test outside transaction
tk.MustExec("insert ignore into tmp1 values(1, 100, 1000) on duplicate key update u=12")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1062 Duplicate entry '12' for key 'tmp1.u'"))
tk.MustQuery("select * from tmp1 where id=1").Check(testkit.Rows("1 11 101"))
tk.MustExec("insert into tmp1 values(2, 100, 1000) on duplicate key update v=202")
tk.MustQuery("show warnings").Check(testkit.Rows())
tk.MustQuery("select * from tmp1 where id=2").Check(testkit.Rows("2 12 202"))
tk.MustExec("insert into tmp1 values(3, 13, 103) on duplicate key update v=203")
tk.MustQuery("show warnings").Check(testkit.Rows())
tk.MustQuery("select * from tmp1 where id=3").Check(testkit.Rows("3 13 103"))
// test in transaction and rollback
tk.MustExec("begin")
tk.MustExec("insert ignore into tmp1 values(1, 100, 1000) on duplicate key update u=12")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1062 Duplicate entry '12' for key 'tmp1.u'"))
tk.MustQuery("select * from tmp1 where id=1").Check(testkit.Rows("1 11 101"))
tk.MustExec("insert into tmp1 values(2, 100, 1000) on duplicate key update v=302")
tk.MustQuery("show warnings").Check(testkit.Rows())
tk.MustQuery("select * from tmp1 where id=2").Check(testkit.Rows("2 12 302"))
tk.MustExec("insert into tmp1 values(4, 14, 104) on duplicate key update v=204")
tk.MustQuery("show warnings").Check(testkit.Rows())
tk.MustQuery("select * from tmp1 where id=4").Check(testkit.Rows("4 14 104"))
tk.MustExec("rollback")
tk.MustQuery("select * from tmp1").Check(testkit.Rows("1 11 101", "2 12 202", "3 13 103"))
// test commit
tk.MustExec("begin")
tk.MustExec("insert ignore into tmp1 values(1, 100, 1000) on duplicate key update u=12")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1062 Duplicate entry '12' for key 'tmp1.u'"))
tk.MustExec("insert into tmp1 values(2, 100, 1000) on duplicate key update v=302")
tk.MustExec("insert into tmp1 values(4, 14, 104) on duplicate key update v=204")
tk.MustExec("commit")
tk.MustQuery("select * from tmp1").Check(testkit.Rows("1 11 101", "2 12 302", "3 13 103", "4 14 104"))
}
func TestLocalTemporaryTableReplace(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create temporary table tmp1 (id int primary key auto_increment, u int unique, v int)")
tk.MustExec("insert into tmp1 values(1, 11, 101)")
tk.MustExec("insert into tmp1 values(2, 12, 102)")
tk.MustExec("insert into tmp1 values(3, 13, 103)")
// out of transaction
tk.MustExec("replace into tmp1 values(1, 12, 1000)")
tk.MustQuery("select * from tmp1").Check(testkit.Rows("1 12 1000", "3 13 103"))
tk.MustExec("replace into tmp1 values(4, 14, 104)")
tk.MustQuery("select * from tmp1 where id=4").Check(testkit.Rows("4 14 104"))
// in transaction and rollback
tk.MustExec("begin")
tk.MustExec("replace into tmp1 values(1, 13, 999)")
tk.MustQuery("select * from tmp1").Check(testkit.Rows("1 13 999", "4 14 104"))
tk.MustExec("replace into tmp1 values(5, 15, 105)")
tk.MustQuery("select * from tmp1 where id=5").Check(testkit.Rows("5 15 105"))
tk.MustExec("rollback")
tk.MustQuery("select * from tmp1").Check(testkit.Rows("1 12 1000", "3 13 103", "4 14 104"))
// out of transaction
tk.MustExec("begin")
tk.MustExec("replace into tmp1 values(1, 13, 999)")
tk.MustExec("replace into tmp1 values(5, 15, 105)")
tk.MustExec("commit")
tk.MustQuery("select * from tmp1").Check(testkit.Rows("1 13 999", "4 14 104", "5 15 105"))
}
func TestLocalTemporaryTableDelete(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create temporary table tmp1 (id int primary key, u int unique, v int)")
insertRecords := func(idList []int) {
for _, id := range idList {
tk.MustExec("insert into tmp1 values (?, ?, ?)", id, id+100, id+1000)
}
}
checkAllExistRecords := func(idList []int) {
sort.Ints(idList)
expectedResult := make([]string, 0, len(idList))
expectedIndexResult := make([]string, 0, len(idList))
for _, id := range idList {
expectedResult = append(expectedResult, fmt.Sprintf("%d %d %d", id, id+100, id+1000))
expectedIndexResult = append(expectedIndexResult, fmt.Sprintf("%d", id+100))
}
tk.MustQuery("select * from tmp1 order by id").Check(testkit.Rows(expectedResult...))
// check index deleted
tk.MustQuery("select /*+ use_index(tmp1, u) */ u from tmp1 order by u").Check(testkit.Rows(expectedIndexResult...))
tk.MustQuery("show warnings").Check(testkit.Rows())
}
assertDelete := func(sql string, deleted []int) {
idList := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
deletedMap := make(map[int]bool)
for _, id := range deleted {
deletedMap[id] = true
}
keepList := make([]int, 0)
for _, id := range idList {
if _, exist := deletedMap[id]; !exist {
keepList = append(keepList, id)
}
}
// delete records in txn and records are inserted in txn
tk.MustExec("begin")
insertRecords(idList)
tk.MustExec(sql)
tk.MustQuery("show warnings").Check(testkit.Rows())
checkAllExistRecords(keepList)
tk.MustExec("rollback")
checkAllExistRecords([]int{})
// delete records out of txn
insertRecords(idList)
tk.MustExec(sql)
checkAllExistRecords(keepList)
// delete records in txn
insertRecords(deleted)
tk.MustExec("begin")
tk.MustExec(sql)
checkAllExistRecords(keepList)
// test rollback
tk.MustExec("rollback")
checkAllExistRecords(idList)
// test commit
tk.MustExec("begin")
tk.MustExec(sql)
tk.MustExec("commit")
checkAllExistRecords(keepList)
tk.MustExec("delete from tmp1")
checkAllExistRecords([]int{})
}
assertDelete("delete from tmp1 where id=1", []int{1})
assertDelete("delete from tmp1 where id in (1, 3, 5)", []int{1, 3, 5})
assertDelete("delete from tmp1 where u=102", []int{2})
assertDelete("delete from tmp1 where u in (103, 107, 108)", []int{3, 7, 8})
assertDelete("delete from tmp1 where id=10", []int{})
assertDelete("delete from tmp1 where id in (10, 12)", []int{})
assertDelete("delete from tmp1 where u=110", []int{})
assertDelete("delete from tmp1 where u in (111, 112)", []int{})
assertDelete("delete from tmp1 where id in (1, 11, 5)", []int{1, 5})
assertDelete("delete from tmp1 where u in (102, 121, 106)", []int{2, 6})
assertDelete("delete from tmp1 where id<3", []int{1, 2})
assertDelete("delete from tmp1 where u>107", []int{8, 9})
assertDelete("delete /*+ use_index(tmp1, u) */ from tmp1 where u>105 and u<107", []int{6})
assertDelete("delete from tmp1 where v>=1006 or v<=1002", []int{1, 2, 6, 7, 8, 9})
}
func TestLocalTemporaryTablePointGet(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create temporary table tmp1 (id int primary key auto_increment, u int unique, v int)")
tk.MustExec("insert into tmp1 values(1, 11, 101)")
tk.MustExec("insert into tmp1 values(2, 12, 102)")
tk.MustExec("insert into tmp1 values(4, 14, 104)")
// check point get out transaction
tk.MustQuery("select * from tmp1 where id=1").Check(testkit.Rows("1 11 101"))
tk.MustQuery("select * from tmp1 where u=11").Check(testkit.Rows("1 11 101"))
tk.MustQuery("select * from tmp1 where id=2").Check(testkit.Rows("2 12 102"))
tk.MustQuery("select * from tmp1 where u=12").Check(testkit.Rows("2 12 102"))
// check point get in transaction
tk.MustExec("begin")
tk.MustQuery("select * from tmp1 where id=1").Check(testkit.Rows("1 11 101"))
tk.MustQuery("select * from tmp1 where u=11").Check(testkit.Rows("1 11 101"))
tk.MustQuery("select * from tmp1 where id=2").Check(testkit.Rows("2 12 102"))
tk.MustQuery("select * from tmp1 where u=12").Check(testkit.Rows("2 12 102"))
tk.MustExec("insert into tmp1 values(3, 13, 103)")
tk.MustQuery("select * from tmp1 where id=3").Check(testkit.Rows("3 13 103"))
tk.MustQuery("select * from tmp1 where u=13").Check(testkit.Rows("3 13 103"))
tk.MustExec("update tmp1 set v=999 where id=2")
tk.MustQuery("select * from tmp1 where id=2").Check(testkit.Rows("2 12 999"))
tk.MustExec("delete from tmp1 where id=4")
tk.MustQuery("select * from tmp1 where id=4").Check(testkit.Rows())
tk.MustQuery("select * from tmp1 where u=14").Check(testkit.Rows())
tk.MustExec("commit")
// check point get after transaction
tk.MustQuery("select * from tmp1 where id=3").Check(testkit.Rows("3 13 103"))
tk.MustQuery("select * from tmp1 where u=13").Check(testkit.Rows("3 13 103"))
tk.MustQuery("select * from tmp1 where id=2").Check(testkit.Rows("2 12 999"))
tk.MustQuery("select * from tmp1 where id=4").Check(testkit.Rows())
tk.MustQuery("select * from tmp1 where u=14").Check(testkit.Rows())
}
func TestLocalTemporaryTableBatchPointGet(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create temporary table tmp1 (id int primary key auto_increment, u int unique, v int)")
tk.MustExec("insert into tmp1 values(1, 11, 101)")
tk.MustExec("insert into tmp1 values(2, 12, 102)")
tk.MustExec("insert into tmp1 values(3, 13, 103)")
tk.MustExec("insert into tmp1 values(4, 14, 104)")
// check point get out transaction
tk.MustQuery("select * from tmp1 where id in (1, 3)").Check(testkit.Rows("1 11 101", "3 13 103"))
tk.MustQuery("select * from tmp1 where u in (11, 13)").Check(testkit.Rows("1 11 101", "3 13 103"))
tk.MustQuery("select * from tmp1 where id in (1, 3, 5)").Check(testkit.Rows("1 11 101", "3 13 103"))
tk.MustQuery("select * from tmp1 where u in (11, 13, 15)").Check(testkit.Rows("1 11 101", "3 13 103"))
// check point get in transaction
tk.MustExec("begin")
tk.MustQuery("select * from tmp1 where id in (1, 3)").Check(testkit.Rows("1 11 101", "3 13 103"))
tk.MustQuery("select * from tmp1 where u in (11, 13)").Check(testkit.Rows("1 11 101", "3 13 103"))
tk.MustQuery("select * from tmp1 where id in (1, 3, 5)").Check(testkit.Rows("1 11 101", "3 13 103"))
tk.MustQuery("select * from tmp1 where u in (11, 13, 15)").Check(testkit.Rows("1 11 101", "3 13 103"))
tk.MustExec("insert into tmp1 values(6, 16, 106)")
tk.MustQuery("select * from tmp1 where id in (1, 6)").Check(testkit.Rows("1 11 101", "6 16 106"))
tk.MustQuery("select * from tmp1 where u in (11, 16)").Check(testkit.Rows("1 11 101", "6 16 106"))
tk.MustExec("update tmp1 set v=999 where id=3")
tk.MustQuery("select * from tmp1 where id in (1, 3)").Check(testkit.Rows("1 11 101", "3 13 999"))
tk.MustQuery("select * from tmp1 where u in (11, 13)").Check(testkit.Rows("1 11 101", "3 13 999"))
tk.MustExec("delete from tmp1 where id=4")
tk.MustQuery("select * from tmp1 where id in (1, 4)").Check(testkit.Rows("1 11 101"))
tk.MustQuery("select * from tmp1 where u in (11, 14)").Check(testkit.Rows("1 11 101"))
tk.MustExec("commit")
// check point get after transaction
tk.MustQuery("select * from tmp1 where id in (1, 3, 6)").Check(testkit.Rows("1 11 101", "3 13 999", "6 16 106"))
tk.MustQuery("select * from tmp1 where u in (11, 13, 16)").Check(testkit.Rows("1 11 101", "3 13 999", "6 16 106"))
tk.MustQuery("select * from tmp1 where id in (1, 4)").Check(testkit.Rows("1 11 101"))
tk.MustQuery("select * from tmp1 where u in (11, 14)").Check(testkit.Rows("1 11 101"))
}
func TestLocalTemporaryTableScan(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create temporary table tmp1 (id int primary key auto_increment, u int unique, v int)")
tk.MustExec("insert into tmp1 values" +
"(1, 101, 1001), (3, 113, 1003), (5, 105, 1005), (7, 117, 1007), (9, 109, 1009)," +
"(10, 110, 1010), (12, 112, 1012), (14, 114, 1014), (16, 116, 1016), (18, 118, 1018)",
)
assertSelectAsUnModified := func() {
// For TableReader
tk.MustQuery("select * from tmp1 where id>3 order by id").Check(testkit.Rows(
"5 105 1005", "7 117 1007", "9 109 1009",
"10 110 1010", "12 112 1012", "14 114 1014", "16 116 1016", "18 118 1018",
))
// For IndexLookUpReader
tk.MustQuery("select /*+ use_index(tmp1, u) */ * from tmp1 where u>101 order by u").Check(testkit.Rows(
"5 105 1005", "9 109 1009", "10 110 1010",
"12 112 1012", "3 113 1003", "14 114 1014", "16 116 1016", "7 117 1007", "18 118 1018",
))
tk.MustQuery("show warnings").Check(testkit.Rows())
// For IndexReader
tk.MustQuery("select /*+ use_index(tmp1, u) */ id,u from tmp1 where u>101 order by id").Check(testkit.Rows(
"3 113", "5 105", "7 117", "9 109", "10 110",
"12 112", "14 114", "16 116", "18 118",
))
tk.MustQuery("show warnings").Check(testkit.Rows())
// For IndexMerge, temporary table should not use index merge
tk.MustQuery("select /*+ use_index_merge(tmp1, primary, u) */ * from tmp1 where id>5 or u>110 order by u").Check(testkit.Rows(
"9 109 1009", "10 110 1010",
"12 112 1012", "3 113 1003", "14 114 1014", "16 116 1016", "7 117 1007", "18 118 1018",
))
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 IndexMerge is inapplicable or disabled. Cannot use IndexMerge on temporary table."))
}
doModify := func() {
tk.MustExec("insert into tmp1 values(2, 100, 1002)")
tk.MustExec("insert into tmp1 values(4, 104, 1004)")
tk.MustExec("insert into tmp1 values(11, 111, 1011)")
tk.MustExec("update tmp1 set v=9999 where id=7")
tk.MustExec("update tmp1 set u=132 where id=12")
tk.MustExec("delete from tmp1 where id=16")
}
assertSelectAsModified := func() {
// For TableReader
tk.MustQuery("select * from tmp1 where id>3 order by id").Check(testkit.Rows(
"4 104 1004", "5 105 1005", "7 117 9999", "9 109 1009",
"10 110 1010", "11 111 1011", "12 132 1012", "14 114 1014", "18 118 1018",
))
// For IndexLookUpReader
tk.MustQuery("select /*+ use_index(tmp1, u) */ * from tmp1 where u>101 order by u").Check(testkit.Rows(
"4 104 1004", "5 105 1005", "9 109 1009", "10 110 1010", "11 111 1011",
"3 113 1003", "14 114 1014", "7 117 9999", "18 118 1018", "12 132 1012",
))
tk.MustQuery("show warnings").Check(testkit.Rows())
// For IndexReader
tk.MustQuery("select /*+ use_index(tmp1, u) */ id,u from tmp1 where u>101 order by id").Check(testkit.Rows(
"3 113", "4 104", "5 105", "7 117", "9 109",
"10 110", "11 111", "12 132", "14 114", "18 118",
))
tk.MustQuery("show warnings").Check(testkit.Rows())
// For IndexMerge, temporary table should not use index merge
tk.MustQuery("select /*+ use_index_merge(tmp1, primary, u) */ * from tmp1 where id>5 or u>110 order by u").Check(testkit.Rows(
"9 109 1009", "10 110 1010", "11 111 1011",
"3 113 1003", "14 114 1014", "7 117 9999", "18 118 1018", "12 132 1012",
))
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 IndexMerge is inapplicable or disabled. Cannot use IndexMerge on temporary table."))
}
assertSelectAsUnModified()
tk.MustExec("begin")
assertSelectAsUnModified()
doModify()
tk.MustExec("rollback")
assertSelectAsUnModified()
tk.MustExec("begin")
doModify()
assertSelectAsModified()
tk.MustExec("commit")
assertSelectAsModified()
}
func TestSchemaCheckerTempTable(t *testing.T) {
store := testkit.CreateMockStoreWithSchemaLease(t, 1*time.Second)
tk1 := testkit.NewTestKit(t, store)
tk2 := testkit.NewTestKit(t, store)
tk1.MustExec("use test")
tk1.MustExec("set global tidb_enable_metadata_lock=0")
tk2.MustExec("use test")
// create table
tk1.MustExec(`drop table if exists normal_table`)
tk1.MustExec(`create table normal_table (id int, c int);`)
defer tk1.MustExec(`drop table if exists normal_table`)
tk1.MustExec(`drop table if exists temp_table`)
tk1.MustExec(`create global temporary table temp_table (id int primary key, c int) on commit delete rows;`)
defer tk1.MustExec(`drop table if exists temp_table`)
// 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)
}()
// It's fine to change the schema of temporary tables.
tk1.MustExec(`begin;`)
tk2.MustExec(`alter table temp_table modify column c tinyint;`)
tk1.MustExec(`insert into temp_table values(3, 3);`)
tk1.MustExec(`commit;`)
tk1.MustExec("begin pessimistic")
tk2.MustExec(`alter table temp_table modify column c int;`)
tk1.MustQuery(`select * from temp_table for update;`).Check(testkit.Rows())
tk1.MustExec(`commit;`)
tk1.MustExec("begin pessimistic")
tk2.MustExec(`alter table temp_table modify column c smallint;`)
tk1.MustExec(`insert into temp_table values(3, 4);`)
tk1.MustQuery(`select * from temp_table for update;`).Check(testkit.Rows("3 4"))
tk1.MustExec(`commit;`)
tk1.MustExec("begin pessimistic")
tk2.MustExec(`alter table temp_table modify column c bigint;`)
tk1.MustQuery(`select * from temp_table where id=1 for update;`).Check(testkit.Rows())
tk1.MustExec(`commit;`)
tk1.MustExec("begin pessimistic")
tk2.MustExec(`alter table temp_table modify column c smallint;`)
tk1.MustExec("insert into temp_table values (1, 2), (2, 3), (4, 5)")
tk1.MustQuery(`select * from temp_table where id=1 for update;`).Check(testkit.Rows("1 2"))
tk1.MustExec(`commit;`)
tk1.MustExec("begin pessimistic")
tk2.MustExec(`alter table temp_table modify column c int;`)
tk1.MustQuery(`select * from temp_table where id=1 for update;`).Check(testkit.Rows())
tk1.MustExec(`commit;`)
tk1.MustExec("begin pessimistic")
tk2.MustExec(`alter table temp_table modify column c bigint;`)
tk1.MustQuery(`select * from temp_table where id in (1, 2, 3) for update;`).Check(testkit.Rows())
tk1.MustExec(`commit;`)
tk1.MustExec("begin pessimistic")
tk2.MustExec(`alter table temp_table modify column c int;`)
tk1.MustExec("insert into temp_table values (1, 2), (2, 3), (4, 5)")
tk1.MustQuery(`select * from temp_table where id in (1, 2, 3) for update;`).Check(testkit.Rows("1 2", "2 3"))
tk1.MustExec(`commit;`)
tk1.MustExec("insert into normal_table values(1, 2)")
tk1.MustExec("begin pessimistic")
tk2.MustExec(`alter table temp_table modify column c int;`)
tk1.MustExec(`insert into temp_table values(1, 5);`)
tk1.MustQuery(`select * from temp_table, normal_table where temp_table.id = normal_table.id for update;`).Check(testkit.Rows("1 5 1 2"))
tk1.MustExec(`commit;`)
tk1.MustExec("begin pessimistic")
tk2.MustExec(`alter table normal_table modify column c bigint;`)
tk1.MustQuery(`select * from temp_table, normal_table where temp_table.id = normal_table.id for update;`).Check(testkit.Rows())
tk1.MustExec(`commit;`)
// Truncate will modify table ID.
tk1.MustExec(`begin;`)
tk2.MustExec(`truncate table temp_table;`)
tk1.MustExec(`insert into temp_table values(3, 3);`)
tk1.MustExec(`commit;`)
// It reports error when also changing the schema of a normal table.
tk1.MustExec(`begin;`)
tk2.MustExec(`alter table normal_table modify column c bigint;`)
tk1.MustExec(`insert into temp_table values(3, 3);`)
tk1.MustExec(`insert into normal_table values(3, 3);`)
err := tk1.ExecToErr(`commit;`)
require.True(t, terror.ErrorEqual(err, domain.ErrInfoSchemaChanged), fmt.Sprintf("err %v", err))
tk1.MustExec("begin pessimistic")
tk2.MustExec(`alter table normal_table modify column c int;`)
tk1.MustExec(`insert into temp_table values(1, 6);`)
tk1.MustQuery(`select * from temp_table, normal_table where temp_table.id = normal_table.id for update;`).Check(testkit.Rows("1 6 1 2"))
err = tk1.ExecToErr(`commit;`)
require.True(t, terror.ErrorEqual(err, domain.ErrInfoSchemaChanged), fmt.Sprintf("err %v", err))
}
func TestSameNameObjectWithLocalTemporaryTable(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t1")
tk.MustExec("drop sequence if exists s1")
tk.MustExec("drop view if exists v1")
// prepare
tk.MustExec("create table t1 (a int)")
defer tk.MustExec("drop table if exists t1")
tk.MustQuery("show create table t1").Check(testkit.Rows(
"t1 CREATE TABLE `t1` (\n" +
" `a` int(11) DEFAULT NULL\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin"))
tk.MustExec("create view v1 as select 1")
defer tk.MustExec("drop view if exists v1")
tk.MustQuery("show create view v1").Check(testkit.Rows("v1 CREATE ALGORITHM=UNDEFINED DEFINER=``@`` SQL SECURITY DEFINER VIEW `v1` (`1`) AS SELECT 1 AS `1` utf8mb4 utf8mb4_bin"))
tk.MustQuery("show create table v1").Check(testkit.Rows("v1 CREATE ALGORITHM=UNDEFINED DEFINER=``@`` SQL SECURITY DEFINER VIEW `v1` (`1`) AS SELECT 1 AS `1` utf8mb4 utf8mb4_bin"))
tk.MustExec("create sequence s1")
defer tk.MustExec("drop sequence if exists s1")
tk.MustQuery("show create sequence s1").Check(testkit.Rows("s1 CREATE SEQUENCE `s1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=InnoDB"))
tk.MustQuery("show create table s1").Check(testkit.Rows("s1 CREATE SEQUENCE `s1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=InnoDB"))
// temp table
tk.MustExec("create temporary table t1 (ct1 int)")
tk.MustQuery("show create table t1").Check(testkit.Rows(
"t1 CREATE TEMPORARY TABLE `t1` (\n" +
" `ct1` int(11) DEFAULT NULL\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin"))
tk.MustExec("create temporary table v1 (cv1 int)")
tk.MustQuery("show create view v1").Check(testkit.Rows("v1 CREATE ALGORITHM=UNDEFINED DEFINER=``@`` SQL SECURITY DEFINER VIEW `v1` (`1`) AS SELECT 1 AS `1` utf8mb4 utf8mb4_bin"))
tk.MustQuery("show create table v1").Check(testkit.Rows(
"v1 CREATE TEMPORARY TABLE `v1` (\n" +
" `cv1` int(11) DEFAULT NULL\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin"))
tk.MustExec("create temporary table s1 (cs1 int)")
tk.MustQuery("show create sequence s1").Check(testkit.Rows("s1 CREATE SEQUENCE `s1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=InnoDB"))
tk.MustQuery("show create table s1").Check(testkit.Rows(
"s1 CREATE TEMPORARY TABLE `s1` (\n" +
" `cs1` int(11) DEFAULT NULL\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin"))
// drop
tk.MustExec("drop view v1")
tk.MustGetErrMsg("show create view v1", "[schema:1146]Table 'test.v1' doesn't exist")
tk.MustQuery("show create table v1").Check(testkit.Rows(
"v1 CREATE TEMPORARY TABLE `v1` (\n" +
" `cv1` int(11) DEFAULT NULL\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin"))
tk.MustExec("drop sequence s1")
tk.MustGetErrMsg("show create sequence s1", "[schema:1146]Table 'test.s1' doesn't exist")
tk.MustQuery("show create table s1").Check(testkit.Rows(
"s1 CREATE TEMPORARY TABLE `s1` (\n" +
" `cs1` int(11) DEFAULT NULL\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin"))
}
func TestLocalTemporaryTableInsertIgnore(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create temporary table tmp1 (id int primary key auto_increment, u int unique, v int)")
tk.MustExec("insert into tmp1 values(1, 11, 101)")
tk.MustExec("insert into tmp1 values(2, 12, 102)")
// test outside transaction
tk.MustExec("insert ignore into tmp1 values(1, 100, 1000)")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1062 Duplicate entry '1' for key 'tmp1.PRIMARY'"))
tk.MustQuery("select * from tmp1 where id=1").Check(testkit.Rows("1 11 101"))
tk.MustExec("insert ignore into tmp1 values(5, 15, 105)")
tk.MustQuery("show warnings").Check(testkit.Rows())
tk.MustQuery("select * from tmp1 where id=5").Check(testkit.Rows("5 15 105"))
// test in transaction and rollback
tk.MustExec("begin")
tk.MustExec("insert ignore into tmp1 values(1, 100, 1000)")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1062 Duplicate entry '1' for key 'tmp1.PRIMARY'"))
tk.MustQuery("select * from tmp1 where id=1").Check(testkit.Rows("1 11 101"))
tk.MustExec("insert ignore into tmp1 values(3, 13, 103)")
tk.MustQuery("show warnings").Check(testkit.Rows())
tk.MustQuery("select * from tmp1 where id=3").Check(testkit.Rows("3 13 103"))
tk.MustExec("insert ignore into tmp1 values(3, 100, 1000)")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1062 Duplicate entry '3' for key 'tmp1.PRIMARY'"))
tk.MustQuery("select * from tmp1 where id=3").Check(testkit.Rows("3 13 103"))
tk.MustExec("rollback")
tk.MustQuery("select * from tmp1").Check(testkit.Rows("1 11 101", "2 12 102", "5 15 105"))
// test commit
tk.MustExec("begin")
tk.MustExec("insert ignore into tmp1 values(1, 100, 1000)")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1062 Duplicate entry '1' for key 'tmp1.PRIMARY'"))
tk.MustExec("insert ignore into tmp1 values(3, 13, 103)")
tk.MustQuery("show warnings").Check(testkit.Rows())
tk.MustExec("insert ignore into tmp1 values(3, 100, 1000)")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1062 Duplicate entry '3' for key 'tmp1.PRIMARY'"))
tk.MustExec("commit")
tk.MustQuery("select * from tmp1").Check(testkit.Rows("1 11 101", "2 12 102", "3 13 103", "5 15 105"))
}