770 lines
25 KiB
Go
770 lines
25 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 autoid_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/pingcap/failpoint"
|
|
_ "github.com/pingcap/tidb/autoid_service"
|
|
ddltestutil "github.com/pingcap/tidb/ddl/testutil"
|
|
"github.com/pingcap/tidb/parser/mysql"
|
|
"github.com/pingcap/tidb/session"
|
|
"github.com/pingcap/tidb/sessionctx/variable"
|
|
"github.com/pingcap/tidb/testkit"
|
|
"github.com/pingcap/tidb/testkit/testutil"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// Test filter different kind of allocators.
|
|
// In special ddl type, for example:
|
|
// 1: ActionRenameTable : it will abandon all the old allocators.
|
|
// 2: ActionRebaseAutoID : it will drop row-id-type allocator.
|
|
// 3: ActionModifyTableAutoIdCache : it will drop row-id-type allocator.
|
|
// 3: ActionRebaseAutoRandomBase : it will drop auto-rand-type allocator.
|
|
func TestFilterDifferentAllocators(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("drop table if exists t1")
|
|
|
|
for _, str := range []string{"", " AUTO_ID_CACHE 1"} {
|
|
tk.MustExec("create table t(a bigint auto_random(5) key, b int auto_increment unique)" + str)
|
|
tk.MustExec("insert into t values()")
|
|
tk.MustQuery("select b from t").Check(testkit.Rows("1"))
|
|
allHandles, err := ddltestutil.ExtractAllTableHandles(tk.Session(), "test", "t")
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(allHandles))
|
|
orderedHandles := testutil.MaskSortHandles(allHandles, 5, mysql.TypeLonglong)
|
|
require.Equal(t, int64(1), orderedHandles[0])
|
|
tk.MustExec("delete from t")
|
|
|
|
// Test rebase auto_increment.
|
|
tk.MustExec("alter table t auto_increment 3000000")
|
|
tk.MustExec("insert into t values()")
|
|
tk.MustQuery("select b from t").Check(testkit.Rows("3000000"))
|
|
allHandles, err = ddltestutil.ExtractAllTableHandles(tk.Session(), "test", "t")
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(allHandles))
|
|
orderedHandles = testutil.MaskSortHandles(allHandles, 5, mysql.TypeLonglong)
|
|
require.Equal(t, int64(2), orderedHandles[0])
|
|
tk.MustExec("delete from t")
|
|
|
|
// Test rebase auto_random.
|
|
tk.MustExec("alter table t auto_random_base 3000000")
|
|
tk.MustExec("insert into t values()")
|
|
tk.MustQuery("select b from t").Check(testkit.Rows("3000001"))
|
|
allHandles, err = ddltestutil.ExtractAllTableHandles(tk.Session(), "test", "t")
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(allHandles))
|
|
orderedHandles = testutil.MaskSortHandles(allHandles, 5, mysql.TypeLonglong)
|
|
require.Equal(t, int64(3000000), orderedHandles[0])
|
|
tk.MustExec("delete from t")
|
|
|
|
// Test rename table.
|
|
tk.MustExec("rename table t to t1")
|
|
tk.MustExec("insert into t1 values()")
|
|
res := tk.MustQuery("select b from t1")
|
|
strInt64, err := strconv.ParseInt(res.Rows()[0][0].(string), 10, 64)
|
|
require.NoError(t, err)
|
|
require.GreaterOrEqual(t, strInt64, int64(3000002))
|
|
allHandles, err = ddltestutil.ExtractAllTableHandles(tk.Session(), "test", "t1")
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(allHandles))
|
|
orderedHandles = testutil.MaskSortHandles(allHandles, 5, mysql.TypeLonglong)
|
|
require.Greater(t, orderedHandles[0], int64(3000001))
|
|
|
|
tk.MustExec("drop table t1")
|
|
}
|
|
}
|
|
|
|
func TestAutoIncrementInsertMinMax(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test")
|
|
|
|
cases := []struct {
|
|
t string
|
|
s string
|
|
vals []int64
|
|
expect [][]interface{}
|
|
}{
|
|
{"tinyint", "signed", []int64{-128, 0, 127}, testkit.Rows("-128", "1", "2", "3", "127")},
|
|
{"tinyint", "unsigned", []int64{0, 127, 255}, testkit.Rows("1", "2", "127", "128", "255")},
|
|
{"smallint", "signed", []int64{-32768, 0, 32767}, testkit.Rows("-32768", "1", "2", "3", "32767")},
|
|
{"smallint", "unsigned", []int64{0, 32767, 65535}, testkit.Rows("1", "2", "32767", "32768", "65535")},
|
|
{"mediumint", "signed", []int64{-8388608, 0, 8388607}, testkit.Rows("-8388608", "1", "2", "3", "8388607")},
|
|
{"mediumint", "unsigned", []int64{0, 8388607, 16777215}, testkit.Rows("1", "2", "8388607", "8388608", "16777215")},
|
|
{"integer", "signed", []int64{-2147483648, 0, 2147483647}, testkit.Rows("-2147483648", "1", "2", "3", "2147483647")},
|
|
{"integer", "unsigned", []int64{0, 2147483647, 4294967295}, testkit.Rows("1", "2", "2147483647", "2147483648", "4294967295")},
|
|
{"bigint", "signed", []int64{-9223372036854775808, 0, 9223372036854775807}, testkit.Rows("-9223372036854775808", "1", "2", "3", "9223372036854775807")},
|
|
{"bigint", "unsigned", []int64{0, 9223372036854775807}, testkit.Rows("1", "2", "9223372036854775807", "9223372036854775808")},
|
|
}
|
|
|
|
for _, option := range []string{"", "auto_id_cache 1", "auto_id_cache 100"} {
|
|
for idx, c := range cases {
|
|
sql := fmt.Sprintf("create table t%d (a %s %s key auto_increment) %s", idx, c.t, c.s, option)
|
|
tk.MustExec(sql)
|
|
|
|
for _, val := range c.vals {
|
|
tk.MustExec(fmt.Sprintf("insert into t%d values (%d)", idx, val))
|
|
tk.Exec(fmt.Sprintf("insert into t%d values ()", idx)) // ignore error
|
|
}
|
|
|
|
tk.MustQuery(fmt.Sprintf("select * from t%d order by a", idx)).Check(c.expect)
|
|
|
|
tk.MustExec(fmt.Sprintf("drop table t%d", idx))
|
|
}
|
|
}
|
|
|
|
tk.MustExec("create table t10 (a integer key auto_increment) auto_id_cache 1")
|
|
err := tk.ExecToErr("insert into t10 values (2147483648)")
|
|
require.Error(t, err)
|
|
err = tk.ExecToErr("insert into t10 values (-2147483649)")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestInsertWithAutoidSchema(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec(`use test`)
|
|
tk.MustExec(`create table t1(id int primary key auto_increment, n int);`)
|
|
tk.MustExec(`create table t2(id int unsigned primary key auto_increment, n int);`)
|
|
tk.MustExec(`create table t3(id tinyint primary key auto_increment, n int);`)
|
|
tk.MustExec(`create table t4(id int primary key, n float auto_increment, key I_n(n));`)
|
|
tk.MustExec(`create table t5(id int primary key, n float unsigned auto_increment, key I_n(n));`)
|
|
tk.MustExec(`create table t6(id int primary key, n double auto_increment, key I_n(n));`)
|
|
tk.MustExec(`create table t7(id int primary key, n double unsigned auto_increment, key I_n(n));`)
|
|
// test for inserting multiple values
|
|
tk.MustExec(`create table t8(id int primary key auto_increment, n int);`)
|
|
|
|
testInsertWithAutoidSchema(t, tk)
|
|
}
|
|
|
|
func TestInsertWithAutoidSchemaCache(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec(`use test`)
|
|
tk.MustExec(`create table t1(id int primary key auto_increment, n int) AUTO_ID_CACHE 1;`)
|
|
tk.MustExec(`create table t2(id int unsigned primary key auto_increment, n int) AUTO_ID_CACHE 1;`)
|
|
tk.MustExec(`create table t3(id tinyint primary key auto_increment, n int) AUTO_ID_CACHE 1;`)
|
|
tk.MustExec(`create table t4(id int primary key, n float auto_increment, key I_n(n)) AUTO_ID_CACHE 1;`)
|
|
tk.MustExec(`create table t5(id int primary key, n float unsigned auto_increment, key I_n(n)) AUTO_ID_CACHE 1;`)
|
|
tk.MustExec(`create table t6(id int primary key, n double auto_increment, key I_n(n)) AUTO_ID_CACHE 1;`)
|
|
tk.MustExec(`create table t7(id int primary key, n double unsigned auto_increment, key I_n(n)) AUTO_ID_CACHE 1;`)
|
|
// test for inserting multiple values
|
|
tk.MustExec(`create table t8(id int primary key auto_increment, n int);`)
|
|
|
|
testInsertWithAutoidSchema(t, tk)
|
|
}
|
|
|
|
func testInsertWithAutoidSchema(t *testing.T, tk *testkit.TestKit) {
|
|
tests := []struct {
|
|
insert string
|
|
query string
|
|
result [][]interface{}
|
|
}{
|
|
{
|
|
`insert into t1(id, n) values(1, 1)`,
|
|
`select * from t1 where id = 1`,
|
|
testkit.Rows(`1 1`),
|
|
},
|
|
{
|
|
`insert into t1(n) values(2)`,
|
|
`select * from t1 where id = 2`,
|
|
testkit.Rows(`2 2`),
|
|
},
|
|
{
|
|
`insert into t1(n) values(3)`,
|
|
`select * from t1 where id = 3`,
|
|
testkit.Rows(`3 3`),
|
|
},
|
|
{
|
|
`insert into t1(id, n) values(-1, 4)`,
|
|
`select * from t1 where id = -1`,
|
|
testkit.Rows(`-1 4`),
|
|
},
|
|
{
|
|
`insert into t1(n) values(5)`,
|
|
`select * from t1 where id = 4`,
|
|
testkit.Rows(`4 5`),
|
|
},
|
|
{
|
|
`insert into t1(id, n) values('5', 6)`,
|
|
`select * from t1 where id = 5`,
|
|
testkit.Rows(`5 6`),
|
|
},
|
|
{
|
|
`insert into t1(n) values(7)`,
|
|
`select * from t1 where id = 6`,
|
|
testkit.Rows(`6 7`),
|
|
},
|
|
{
|
|
`insert into t1(id, n) values(7.4, 8)`,
|
|
`select * from t1 where id = 7`,
|
|
testkit.Rows(`7 8`),
|
|
},
|
|
{
|
|
`insert into t1(id, n) values(7.5, 9)`,
|
|
`select * from t1 where id = 8`,
|
|
testkit.Rows(`8 9`),
|
|
},
|
|
{
|
|
`insert into t1(n) values(9)`,
|
|
`select * from t1 where id = 9`,
|
|
testkit.Rows(`9 9`),
|
|
},
|
|
// test last insert id
|
|
{
|
|
`insert into t1 values(3000, -1), (null, -2)`,
|
|
`select * from t1 where id = 3000`,
|
|
testkit.Rows(`3000 -1`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select * from t1 where id = 3001`,
|
|
testkit.Rows(`3001 -2`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select last_insert_id()`,
|
|
testkit.Rows(`3001`),
|
|
},
|
|
{
|
|
`insert into t2(id, n) values(1, 1)`,
|
|
`select * from t2 where id = 1`,
|
|
testkit.Rows(`1 1`),
|
|
},
|
|
{
|
|
`insert into t2(n) values(2)`,
|
|
`select * from t2 where id = 2`,
|
|
testkit.Rows(`2 2`),
|
|
},
|
|
{
|
|
`insert into t2(n) values(3)`,
|
|
`select * from t2 where id = 3`,
|
|
testkit.Rows(`3 3`),
|
|
},
|
|
{
|
|
`insert into t3(id, n) values(1, 1)`,
|
|
`select * from t3 where id = 1`,
|
|
testkit.Rows(`1 1`),
|
|
},
|
|
{
|
|
`insert into t3(n) values(2)`,
|
|
`select * from t3 where id = 2`,
|
|
testkit.Rows(`2 2`),
|
|
},
|
|
{
|
|
`insert into t3(n) values(3)`,
|
|
`select * from t3 where id = 3`,
|
|
testkit.Rows(`3 3`),
|
|
},
|
|
{
|
|
`insert into t3(id, n) values(-1, 4)`,
|
|
`select * from t3 where id = -1`,
|
|
testkit.Rows(`-1 4`),
|
|
},
|
|
{
|
|
`insert into t3(n) values(5)`,
|
|
`select * from t3 where id = 4`,
|
|
testkit.Rows(`4 5`),
|
|
},
|
|
{
|
|
`insert into t4(id, n) values(1, 1)`,
|
|
`select * from t4 where id = 1`,
|
|
testkit.Rows(`1 1`),
|
|
},
|
|
{
|
|
`insert into t4(id) values(2)`,
|
|
`select * from t4 where id = 2`,
|
|
testkit.Rows(`2 2`),
|
|
},
|
|
{
|
|
`insert into t4(id, n) values(3, -1)`,
|
|
`select * from t4 where id = 3`,
|
|
testkit.Rows(`3 -1`),
|
|
},
|
|
{
|
|
`insert into t4(id) values(4)`,
|
|
`select * from t4 where id = 4`,
|
|
testkit.Rows(`4 3`),
|
|
},
|
|
{
|
|
`insert into t4(id, n) values(5, 5.5)`,
|
|
`select * from t4 where id = 5`,
|
|
testkit.Rows(`5 5.5`),
|
|
},
|
|
{
|
|
`insert into t4(id) values(6)`,
|
|
`select * from t4 where id = 6`,
|
|
testkit.Rows(`6 7`),
|
|
},
|
|
{
|
|
`insert into t4(id, n) values(7, '7.7')`,
|
|
`select * from t4 where id = 7`,
|
|
testkit.Rows(`7 7.7`),
|
|
},
|
|
{
|
|
`insert into t4(id) values(8)`,
|
|
`select * from t4 where id = 8`,
|
|
testkit.Rows(`8 9`),
|
|
},
|
|
{
|
|
`insert into t4(id, n) values(9, 10.4)`,
|
|
`select * from t4 where id = 9`,
|
|
testkit.Rows(`9 10.4`),
|
|
},
|
|
{
|
|
`insert into t4(id) values(10)`,
|
|
`select * from t4 where id = 10`,
|
|
testkit.Rows(`10 11`),
|
|
},
|
|
{
|
|
`insert into t5(id, n) values(1, 1)`,
|
|
`select * from t5 where id = 1`,
|
|
testkit.Rows(`1 1`),
|
|
},
|
|
{
|
|
`insert into t5(id) values(2)`,
|
|
`select * from t5 where id = 2`,
|
|
testkit.Rows(`2 2`),
|
|
},
|
|
{
|
|
`insert into t5(id) values(3)`,
|
|
`select * from t5 where id = 3`,
|
|
testkit.Rows(`3 3`),
|
|
},
|
|
{
|
|
`insert into t6(id, n) values(1, 1)`,
|
|
`select * from t6 where id = 1`,
|
|
testkit.Rows(`1 1`),
|
|
},
|
|
{
|
|
`insert into t6(id) values(2)`,
|
|
`select * from t6 where id = 2`,
|
|
testkit.Rows(`2 2`),
|
|
},
|
|
{
|
|
`insert into t6(id, n) values(3, -1)`,
|
|
`select * from t6 where id = 3`,
|
|
testkit.Rows(`3 -1`),
|
|
},
|
|
{
|
|
`insert into t6(id) values(4)`,
|
|
`select * from t6 where id = 4`,
|
|
testkit.Rows(`4 3`),
|
|
},
|
|
{
|
|
`insert into t6(id, n) values(5, 5.5)`,
|
|
`select * from t6 where id = 5`,
|
|
testkit.Rows(`5 5.5`),
|
|
},
|
|
{
|
|
`insert into t6(id) values(6)`,
|
|
`select * from t6 where id = 6`,
|
|
testkit.Rows(`6 7`),
|
|
},
|
|
{
|
|
`insert into t6(id, n) values(7, '7.7')`,
|
|
`select * from t4 where id = 7`,
|
|
testkit.Rows(`7 7.7`),
|
|
},
|
|
{
|
|
`insert into t6(id) values(8)`,
|
|
`select * from t4 where id = 8`,
|
|
testkit.Rows(`8 9`),
|
|
},
|
|
{
|
|
`insert into t6(id, n) values(9, 10.4)`,
|
|
`select * from t6 where id = 9`,
|
|
testkit.Rows(`9 10.4`),
|
|
},
|
|
{
|
|
`insert into t6(id) values(10)`,
|
|
`select * from t6 where id = 10`,
|
|
testkit.Rows(`10 11`),
|
|
},
|
|
{
|
|
`insert into t7(id, n) values(1, 1)`,
|
|
`select * from t7 where id = 1`,
|
|
testkit.Rows(`1 1`),
|
|
},
|
|
{
|
|
`insert into t7(id) values(2)`,
|
|
`select * from t7 where id = 2`,
|
|
testkit.Rows(`2 2`),
|
|
},
|
|
{
|
|
`insert into t7(id) values(3)`,
|
|
`select * from t7 where id = 3`,
|
|
testkit.Rows(`3 3`),
|
|
},
|
|
|
|
// the following is test for insert multiple values.
|
|
{
|
|
`insert into t8(n) values(1),(2)`,
|
|
`select * from t8 where id = 1`,
|
|
testkit.Rows(`1 1`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select * from t8 where id = 2`,
|
|
testkit.Rows(`2 2`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select last_insert_id();`,
|
|
testkit.Rows(`1`),
|
|
},
|
|
// test user rebase and auto alloc mixture.
|
|
{
|
|
`insert into t8 values(null, 3),(-1, -1),(null,4),(null, 5)`,
|
|
`select * from t8 where id = 3`,
|
|
testkit.Rows(`3 3`),
|
|
},
|
|
// -1 won't rebase allocator here cause -1 < base.
|
|
{
|
|
`;`,
|
|
`select * from t8 where id = -1`,
|
|
testkit.Rows(`-1 -1`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select * from t8 where id = 4`,
|
|
testkit.Rows(`4 4`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select * from t8 where id = 5`,
|
|
testkit.Rows(`5 5`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select last_insert_id();`,
|
|
testkit.Rows(`3`),
|
|
},
|
|
{
|
|
`insert into t8 values(null, 6),(10, 7),(null, 8)`,
|
|
`select * from t8 where id = 6`,
|
|
testkit.Rows(`6 6`),
|
|
},
|
|
// 10 will rebase allocator here.
|
|
{
|
|
`;`,
|
|
`select * from t8 where id = 10`,
|
|
testkit.Rows(`10 7`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select * from t8 where id = 11`,
|
|
testkit.Rows(`11 8`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select last_insert_id()`,
|
|
testkit.Rows(`6`),
|
|
},
|
|
// fix bug for last_insert_id should be first allocated id in insert rows (skip the rebase id).
|
|
{
|
|
`insert into t8 values(100, 9),(null,10),(null,11)`,
|
|
`select * from t8 where id = 100`,
|
|
testkit.Rows(`100 9`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select * from t8 where id = 101`,
|
|
testkit.Rows(`101 10`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select * from t8 where id = 102`,
|
|
testkit.Rows(`102 11`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select last_insert_id()`,
|
|
testkit.Rows(`101`),
|
|
},
|
|
// test with sql_mode: NO_AUTO_VALUE_ON_ZERO.
|
|
{
|
|
`;`,
|
|
`select @@sql_mode`,
|
|
testkit.Rows(`ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION`),
|
|
},
|
|
{
|
|
`;`,
|
|
"set session sql_mode = `ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,NO_AUTO_VALUE_ON_ZERO`",
|
|
nil,
|
|
},
|
|
{
|
|
`insert into t8 values (0, 12), (null, 13)`,
|
|
`select * from t8 where id = 0`,
|
|
testkit.Rows(`0 12`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select * from t8 where id = 103`,
|
|
testkit.Rows(`103 13`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select last_insert_id()`,
|
|
testkit.Rows(`103`),
|
|
},
|
|
// test without sql_mode: NO_AUTO_VALUE_ON_ZERO.
|
|
{
|
|
`;`,
|
|
"set session sql_mode = `ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION`",
|
|
nil,
|
|
},
|
|
// value 0 will be substitute by autoid.
|
|
{
|
|
`insert into t8 values (0, 14), (null, 15)`,
|
|
`select * from t8 where id = 104`,
|
|
testkit.Rows(`104 14`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select * from t8 where id = 105`,
|
|
testkit.Rows(`105 15`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select last_insert_id()`,
|
|
testkit.Rows(`104`),
|
|
},
|
|
// last test : auto increment allocation can find in retryInfo.
|
|
{
|
|
`retry : insert into t8 values (null, 16), (null, 17)`,
|
|
`select * from t8 where id = 1000`,
|
|
testkit.Rows(`1000 16`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select * from t8 where id = 1001`,
|
|
testkit.Rows(`1001 17`),
|
|
},
|
|
{
|
|
`;`,
|
|
`select last_insert_id()`,
|
|
// this insert doesn't has the last_insert_id, should be same as the last insert case.
|
|
testkit.Rows(`104`),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
if strings.HasPrefix(tt.insert, "retry : ") {
|
|
// it's the last retry insert case, change the sessionVars.
|
|
retryInfo := &variable.RetryInfo{Retrying: true}
|
|
retryInfo.AddAutoIncrementID(1000)
|
|
retryInfo.AddAutoIncrementID(1001)
|
|
tk.Session().GetSessionVars().RetryInfo = retryInfo
|
|
tk.MustExec(tt.insert[8:])
|
|
tk.Session().GetSessionVars().RetryInfo = &variable.RetryInfo{}
|
|
} else {
|
|
tk.MustExec(tt.insert)
|
|
}
|
|
if tt.query == "set session sql_mode = `ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,NO_AUTO_VALUE_ON_ZERO`" ||
|
|
tt.query == "set session sql_mode = `ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION`" {
|
|
tk.MustExec(tt.query)
|
|
} else {
|
|
tk.MustQuery(tt.query).Check(tt.result)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestAutoIDIncrementAndOffset There is a potential issue in MySQL: when the value of auto_increment_offset is greater
|
|
// than that of auto_increment_increment, the value of auto_increment_offset is ignored
|
|
// (https://dev.mysql.com/doc/refman/8.0/en/replication-options-master.html#sysvar_auto_increment_increment),
|
|
// This issue is a flaw of the implementation of MySQL and it doesn't exist in TiDB.
|
|
func TestAutoIDIncrementAndOffset(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec(`use test`)
|
|
// Test for offset is larger than increment.
|
|
tk.Session().GetSessionVars().AutoIncrementIncrement = 5
|
|
tk.Session().GetSessionVars().AutoIncrementOffset = 10
|
|
|
|
for _, str := range []string{"", " AUTO_ID_CACHE 1"} {
|
|
tk.MustExec(`create table io (a int key auto_increment)` + str)
|
|
tk.MustExec(`insert into io values (null),(null),(null)`)
|
|
tk.MustQuery(`select * from io`).Check(testkit.Rows("10", "15", "20"))
|
|
tk.MustExec(`drop table io`)
|
|
}
|
|
|
|
// Test handle is PK.
|
|
for _, str := range []string{"", " AUTO_ID_CACHE 1"} {
|
|
tk.MustExec(`create table io (a int key auto_increment)` + str)
|
|
tk.Session().GetSessionVars().AutoIncrementOffset = 10
|
|
tk.Session().GetSessionVars().AutoIncrementIncrement = 2
|
|
tk.MustExec(`insert into io values (),(),()`)
|
|
tk.MustQuery(`select * from io`).Check(testkit.Rows("10", "12", "14"))
|
|
tk.MustExec(`delete from io`)
|
|
|
|
// Test reset the increment.
|
|
tk.Session().GetSessionVars().AutoIncrementIncrement = 5
|
|
tk.MustExec(`insert into io values (),(),()`)
|
|
tk.MustQuery(`select * from io`).Check(testkit.Rows("15", "20", "25"))
|
|
tk.MustExec(`delete from io`)
|
|
|
|
tk.Session().GetSessionVars().AutoIncrementIncrement = 10
|
|
tk.MustExec(`insert into io values (),(),()`)
|
|
tk.MustQuery(`select * from io`).Check(testkit.Rows("30", "40", "50"))
|
|
tk.MustExec(`delete from io`)
|
|
|
|
tk.Session().GetSessionVars().AutoIncrementIncrement = 5
|
|
tk.MustExec(`insert into io values (),(),()`)
|
|
tk.MustQuery(`select * from io`).Check(testkit.Rows("55", "60", "65"))
|
|
tk.MustExec(`drop table io`)
|
|
}
|
|
|
|
// Test handle is not PK.
|
|
for _, str := range []string{"", " AUTO_ID_CACHE 1"} {
|
|
tk.Session().GetSessionVars().AutoIncrementIncrement = 2
|
|
tk.Session().GetSessionVars().AutoIncrementOffset = 10
|
|
tk.MustExec(`create table io (a int, b int auto_increment, key(b))` + str)
|
|
tk.MustExec(`insert into io(b) values (null),(null),(null)`)
|
|
// AutoID allocation will take increment and offset into consideration.
|
|
tk.MustQuery(`select b from io`).Check(testkit.Rows("10", "12", "14"))
|
|
if str == "" {
|
|
// HandleID allocation will ignore the increment and offset.
|
|
tk.MustQuery(`select _tidb_rowid from io`).Check(testkit.Rows("15", "16", "17"))
|
|
} else {
|
|
// Separate row id and auto inc id, increment and offset works on auto inc id
|
|
tk.MustQuery(`select _tidb_rowid from io`).Check(testkit.Rows("1", "2", "3"))
|
|
}
|
|
tk.MustExec(`delete from io`)
|
|
|
|
tk.Session().GetSessionVars().AutoIncrementIncrement = 10
|
|
tk.MustExec(`insert into io(b) values (null),(null),(null)`)
|
|
tk.MustQuery(`select b from io`).Check(testkit.Rows("20", "30", "40"))
|
|
if str == "" {
|
|
tk.MustQuery(`select _tidb_rowid from io`).Check(testkit.Rows("41", "42", "43"))
|
|
} else {
|
|
tk.MustQuery(`select _tidb_rowid from io`).Check(testkit.Rows("4", "5", "6"))
|
|
}
|
|
|
|
// Test invalid value.
|
|
tk.Session().GetSessionVars().AutoIncrementIncrement = -1
|
|
tk.Session().GetSessionVars().AutoIncrementOffset = -2
|
|
tk.MustGetErrMsg(`insert into io(b) values (null),(null),(null)`,
|
|
"[autoid:8060]Invalid auto_increment settings: auto_increment_increment: -1, auto_increment_offset: -2, both of them must be in range [1..65535]")
|
|
tk.MustExec(`delete from io`)
|
|
|
|
tk.Session().GetSessionVars().AutoIncrementIncrement = 65536
|
|
tk.Session().GetSessionVars().AutoIncrementOffset = 65536
|
|
tk.MustGetErrMsg(`insert into io(b) values (null),(null),(null)`,
|
|
"[autoid:8060]Invalid auto_increment settings: auto_increment_increment: 65536, auto_increment_offset: 65536, both of them must be in range [1..65535]")
|
|
|
|
tk.MustExec(`drop table io`)
|
|
}
|
|
}
|
|
|
|
func TestRenameTableForAutoIncrement(t *testing.T) {
|
|
store, _ := testkit.CreateMockStoreAndDomain(t)
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("USE test;")
|
|
tk.MustExec("drop table if exists t1, t2, t3;")
|
|
tk.MustExec("create table t1 (id int key auto_increment);")
|
|
tk.MustExec("insert into t1 values ()")
|
|
tk.MustExec("rename table t1 to t11")
|
|
tk.MustExec("insert into t11 values ()")
|
|
// TODO(tiancaiamao): fix bug and uncomment here, rename table should not discard the cached AUTO_ID.
|
|
// tk.MustQuery("select * from t11").Check(testkit.Rows("1", "2"))
|
|
|
|
// auto_id_cache 1 use another implementation and do not have such bug.
|
|
tk.MustExec("create table t2 (id int key auto_increment) auto_id_cache 1;")
|
|
tk.MustExec("insert into t2 values ()")
|
|
tk.MustExec("rename table t2 to t22")
|
|
tk.MustExec("insert into t22 values ()")
|
|
tk.MustQuery("select * from t22").Check(testkit.Rows("1", "2"))
|
|
|
|
tk.MustExec("create table t3 (id int key auto_increment) auto_id_cache 100;")
|
|
tk.MustExec("insert into t3 values ()")
|
|
tk.MustExec("rename table t3 to t33")
|
|
tk.MustExec("insert into t33 values ()")
|
|
// TODO(tiancaiamao): fix bug and uncomment here, rename table should not discard the cached AUTO_ID.
|
|
// tk.MustQuery("select * from t33").Check(testkit.Rows("1", "2"))
|
|
}
|
|
|
|
func TestAlterTableAutoIDCache(t *testing.T) {
|
|
store, _ := testkit.CreateMockStoreAndDomain(t)
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("USE test;")
|
|
tk.MustExec("drop table if exists t_473;")
|
|
tk.MustExec("create table t_473 (id int key auto_increment)")
|
|
tk.MustExec("insert into t_473 values ()")
|
|
tk.MustQuery("select * from t_473").Check(testkit.Rows("1"))
|
|
rs, err := tk.Exec("show table t_473 next_row_id")
|
|
require.NoError(t, err)
|
|
rows, err1 := session.ResultSetToStringSlice(context.Background(), tk.Session(), rs)
|
|
require.NoError(t, err1)
|
|
// "test t_473 id 1013608 AUTO_INCREMENT"
|
|
val, err2 := strconv.ParseUint(rows[0][3], 10, 64)
|
|
require.NoError(t, err2)
|
|
|
|
tk.MustExec("alter table t_473 auto_id_cache = 100")
|
|
tk.MustQuery("show table t_473 next_row_id").Check(testkit.Rows(
|
|
fmt.Sprintf("test t_473 id %d _TIDB_ROWID", val),
|
|
"test t_473 id 1 AUTO_INCREMENT",
|
|
))
|
|
tk.MustExec("insert into t_473 values ()")
|
|
tk.MustQuery("select * from t_473").Check(testkit.Rows("1", fmt.Sprintf("%d", val)))
|
|
tk.MustQuery("show table t_473 next_row_id").Check(testkit.Rows(
|
|
fmt.Sprintf("test t_473 id %d _TIDB_ROWID", val+100),
|
|
"test t_473 id 1 AUTO_INCREMENT",
|
|
))
|
|
|
|
// Note that auto_id_cache=1 use a different implementation, switch between them is not allowed.
|
|
// TODO: relax this restriction and update the test case.
|
|
tk.MustExecToErr("alter table t_473 auto_id_cache = 1")
|
|
}
|
|
|
|
func TestMockAutoIDServiceError(t *testing.T) {
|
|
store := testkit.CreateMockStore(t)
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("USE test;")
|
|
tk.MustExec("create table t_mock_err (id int key auto_increment) auto_id_cache 1")
|
|
|
|
failpoint.Enable("github.com/pingcap/tidb/autoid_service/mockErr", `return(true)`)
|
|
defer failpoint.Disable("github.com/pingcap/tidb/autoid_service/mockErr")
|
|
// Cover a bug that the autoid client retry non-retryable errors forever cause dead loop.
|
|
tk.MustExecToErr("insert into t_mock_err values (),()") // mock error, instead of dead loop
|
|
}
|
|
|
|
func TestIssue39528(t *testing.T) {
|
|
// When AUTO_ID_CACHE is 1, it should not affect row id setting when autoid and rowid are separated.
|
|
store := testkit.CreateMockStore(t)
|
|
tk := testkit.NewTestKit(t, store)
|
|
tk.MustExec("use test;")
|
|
tk.MustExec("create table issue39528 (id int unsigned key nonclustered auto_increment) shard_row_id_bits=4 auto_id_cache 1;")
|
|
tk.MustExec("insert into issue39528 values ()")
|
|
tk.MustExec("insert into issue39528 values ()")
|
|
|
|
ctx := context.Background()
|
|
var codeRun bool
|
|
ctx = context.WithValue(ctx, "testIssue39528", &codeRun)
|
|
_, err := tk.ExecWithContext(ctx, "insert into issue39528 values ()")
|
|
require.NoError(t, err)
|
|
// Make sure the code does not visit tikv on allocate path.
|
|
require.False(t, codeRun)
|
|
}
|