Files
tidb/executor/test/partitiontest/partition_test.go

495 lines
19 KiB
Go

// Copyright 2023 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 partitiontest
import (
"fmt"
"testing"
"github.com/pingcap/failpoint"
"github.com/pingcap/tidb/testkit"
"github.com/stretchr/testify/require"
)
func TestPartitionedTableReplace(t *testing.T) {
failpoint.Enable("github.com/pingcap/tidb/planner/core/forceDynamicPrune", `return(true)`)
defer failpoint.Disable("github.com/pingcap/tidb/planner/core/forceDynamicPrune")
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
testSQL := `drop table if exists replace_test;
create table replace_test (id int PRIMARY KEY AUTO_INCREMENT, c1 int, c2 int, c3 int default 1)
partition by range (id) (
PARTITION p0 VALUES LESS THAN (3),
PARTITION p1 VALUES LESS THAN (5),
PARTITION p2 VALUES LESS THAN (7),
PARTITION p3 VALUES LESS THAN (9));`
tk.MustExec(testSQL)
testSQL = `replace replace_test (c1) values (1),(2),(NULL);`
tk.MustExec(testSQL)
require.Equal(t, tk.Session().LastMessage(), "Records: 3 Duplicates: 0 Warnings: 0")
errReplaceSQL := `replace replace_test (c1) values ();`
tk.MustExec("begin")
err := tk.ExecToErr(errReplaceSQL)
require.Error(t, err)
tk.MustExec("rollback")
errReplaceSQL = `replace replace_test (c1, c2) values (1,2),(1);`
tk.MustExec("begin")
err = tk.ExecToErr(errReplaceSQL)
require.Error(t, err)
tk.MustExec("rollback")
errReplaceSQL = `replace replace_test (xxx) values (3);`
tk.MustExec("begin")
err = tk.ExecToErr(errReplaceSQL)
require.Error(t, err)
tk.MustExec("rollback")
errReplaceSQL = `replace replace_test_xxx (c1) values ();`
tk.MustExec("begin")
err = tk.ExecToErr(errReplaceSQL)
require.Error(t, err)
tk.MustExec("rollback")
replaceSetSQL := `replace replace_test set c1 = 3;`
tk.MustExec(replaceSetSQL)
require.Empty(t, tk.Session().LastMessage())
errReplaceSetSQL := `replace replace_test set c1 = 4, c1 = 5;`
tk.MustExec("begin")
err = tk.ExecToErr(errReplaceSetSQL)
require.Error(t, err)
tk.MustExec("rollback")
errReplaceSetSQL = `replace replace_test set xxx = 6;`
tk.MustExec("begin")
err = tk.ExecToErr(errReplaceSetSQL)
require.Error(t, err)
tk.MustExec("rollback")
tk.MustExec(`drop table if exists replace_test_1`)
tk.MustExec(`create table replace_test_1 (id int, c1 int) partition by range (id) (
PARTITION p0 VALUES LESS THAN (4),
PARTITION p1 VALUES LESS THAN (6),
PARTITION p2 VALUES LESS THAN (8),
PARTITION p3 VALUES LESS THAN (10),
PARTITION p4 VALUES LESS THAN (100))`)
tk.MustExec(`replace replace_test_1 select id, c1 from replace_test;`)
require.Equal(t, tk.Session().LastMessage(), "Records: 4 Duplicates: 0 Warnings: 0")
tk.MustExec(`drop table if exists replace_test_2`)
tk.MustExec(`create table replace_test_2 (id int, c1 int) partition by range (id) (
PARTITION p0 VALUES LESS THAN (10),
PARTITION p1 VALUES LESS THAN (50),
PARTITION p2 VALUES LESS THAN (100),
PARTITION p3 VALUES LESS THAN (300))`)
tk.MustExec(`replace replace_test_1 select id, c1 from replace_test union select id * 10, c1 * 10 from replace_test;`)
require.Equal(t, tk.Session().LastMessage(), "Records: 8 Duplicates: 0 Warnings: 0")
errReplaceSelectSQL := `replace replace_test_1 select c1 from replace_test;`
tk.MustExec("begin")
err = tk.ExecToErr(errReplaceSelectSQL)
require.Error(t, err)
tk.MustExec("rollback")
tk.MustExec(`drop table if exists replace_test_3`)
replaceUniqueIndexSQL := `create table replace_test_3 (c1 int, c2 int, UNIQUE INDEX (c2)) partition by range (c2) (
PARTITION p0 VALUES LESS THAN (4),
PARTITION p1 VALUES LESS THAN (7),
PARTITION p2 VALUES LESS THAN (11))`
tk.MustExec(replaceUniqueIndexSQL)
replaceUniqueIndexSQL = `replace into replace_test_3 set c2=8;`
tk.MustExec(replaceUniqueIndexSQL)
replaceUniqueIndexSQL = `replace into replace_test_3 set c2=8;`
tk.MustExec(replaceUniqueIndexSQL)
require.Equal(t, int64(1), int64(tk.Session().AffectedRows()))
require.Empty(t, tk.Session().LastMessage())
replaceUniqueIndexSQL = `replace into replace_test_3 set c1=8, c2=8;`
tk.MustExec(replaceUniqueIndexSQL)
require.Equal(t, int64(2), int64(tk.Session().AffectedRows()))
require.Empty(t, tk.Session().LastMessage())
replaceUniqueIndexSQL = `replace into replace_test_3 set c2=NULL;`
tk.MustExec(replaceUniqueIndexSQL)
replaceUniqueIndexSQL = `replace into replace_test_3 set c2=NULL;`
tk.MustExec(replaceUniqueIndexSQL)
require.Equal(t, int64(1), int64(tk.Session().AffectedRows()))
require.Empty(t, tk.Session().LastMessage())
replaceUniqueIndexSQL = `create table replace_test_4 (c1 int, c2 int, c3 int, UNIQUE INDEX (c1, c2)) partition by range (c1) (
PARTITION p0 VALUES LESS THAN (4),
PARTITION p1 VALUES LESS THAN (7),
PARTITION p2 VALUES LESS THAN (11));`
tk.MustExec(`drop table if exists replace_test_4`)
tk.MustExec(replaceUniqueIndexSQL)
replaceUniqueIndexSQL = `replace into replace_test_4 set c2=NULL;`
tk.MustExec(replaceUniqueIndexSQL)
replaceUniqueIndexSQL = `replace into replace_test_4 set c2=NULL;`
tk.MustExec(replaceUniqueIndexSQL)
require.Equal(t, int64(1), int64(tk.Session().AffectedRows()))
replacePrimaryKeySQL := `create table replace_test_5 (c1 int, c2 int, c3 int, PRIMARY KEY (c1, c2)) partition by range (c2) (
PARTITION p0 VALUES LESS THAN (4),
PARTITION p1 VALUES LESS THAN (7),
PARTITION p2 VALUES LESS THAN (11));`
tk.MustExec(replacePrimaryKeySQL)
replacePrimaryKeySQL = `replace into replace_test_5 set c1=1, c2=2;`
tk.MustExec(replacePrimaryKeySQL)
replacePrimaryKeySQL = `replace into replace_test_5 set c1=1, c2=2;`
tk.MustExec(replacePrimaryKeySQL)
require.Equal(t, int64(1), int64(tk.Session().AffectedRows()))
issue989SQL := `CREATE TABLE tIssue989 (a int, b int, KEY(a), UNIQUE KEY(b)) partition by range (b) (
PARTITION p1 VALUES LESS THAN (100),
PARTITION p2 VALUES LESS THAN (200))`
tk.MustExec(issue989SQL)
issue989SQL = `insert into tIssue989 (a, b) values (1, 2);`
tk.MustExec(issue989SQL)
issue989SQL = `replace into tIssue989(a, b) values (111, 2);`
tk.MustExec(issue989SQL)
r := tk.MustQuery("select * from tIssue989;")
r.Check(testkit.Rows("111 2"))
}
func TestHashPartitionedTableReplace(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("set @@session.tidb_enable_table_partition = '1';")
tk.MustExec("drop table if exists replace_test;")
testSQL := `create table replace_test (id int PRIMARY KEY AUTO_INCREMENT, c1 int, c2 int, c3 int default 1)
partition by hash(id) partitions 4;`
tk.MustExec(testSQL)
testSQL = `replace replace_test (c1) values (1),(2),(NULL);`
tk.MustExec(testSQL)
errReplaceSQL := `replace replace_test (c1) values ();`
tk.MustExec("begin")
err := tk.ExecToErr(errReplaceSQL)
require.Error(t, err)
tk.MustExec("rollback")
errReplaceSQL = `replace replace_test (c1, c2) values (1,2),(1);`
tk.MustExec("begin")
err = tk.ExecToErr(errReplaceSQL)
require.Error(t, err)
tk.MustExec("rollback")
errReplaceSQL = `replace replace_test (xxx) values (3);`
tk.MustExec("begin")
err = tk.ExecToErr(errReplaceSQL)
require.Error(t, err)
tk.MustExec("rollback")
errReplaceSQL = `replace replace_test_xxx (c1) values ();`
tk.MustExec("begin")
err = tk.ExecToErr(errReplaceSQL)
require.Error(t, err)
tk.MustExec("rollback")
errReplaceSetSQL := `replace replace_test set c1 = 4, c1 = 5;`
tk.MustExec("begin")
err = tk.ExecToErr(errReplaceSetSQL)
require.Error(t, err)
tk.MustExec("rollback")
errReplaceSetSQL = `replace replace_test set xxx = 6;`
tk.MustExec("begin")
err = tk.ExecToErr(errReplaceSetSQL)
require.Error(t, err)
tk.MustExec("rollback")
tk.MustExec(`replace replace_test set c1 = 3;`)
tk.MustExec(`replace replace_test set c1 = 4;`)
tk.MustExec(`replace replace_test set c1 = 5;`)
tk.MustExec(`replace replace_test set c1 = 6;`)
tk.MustExec(`replace replace_test set c1 = 7;`)
tk.MustExec(`drop table if exists replace_test_1`)
tk.MustExec(`create table replace_test_1 (id int, c1 int) partition by hash(id) partitions 5;`)
tk.MustExec(`replace replace_test_1 select id, c1 from replace_test;`)
tk.MustExec(`drop table if exists replace_test_2`)
tk.MustExec(`create table replace_test_2 (id int, c1 int) partition by hash(id) partitions 6;`)
tk.MustExec(`replace replace_test_1 select id, c1 from replace_test union select id * 10, c1 * 10 from replace_test;`)
errReplaceSelectSQL := `replace replace_test_1 select c1 from replace_test;`
tk.MustExec("begin")
err = tk.ExecToErr(errReplaceSelectSQL)
require.Error(t, err)
tk.MustExec("rollback")
tk.MustExec(`drop table if exists replace_test_3`)
replaceUniqueIndexSQL := `create table replace_test_3 (c1 int, c2 int, UNIQUE INDEX (c2)) partition by hash(c2) partitions 7;`
tk.MustExec(replaceUniqueIndexSQL)
tk.MustExec(`replace into replace_test_3 set c2=8;`)
tk.MustExec(`replace into replace_test_3 set c2=8;`)
require.Equal(t, int64(1), int64(tk.Session().AffectedRows()))
tk.MustExec(`replace into replace_test_3 set c1=8, c2=8;`)
require.Equal(t, int64(2), int64(tk.Session().AffectedRows()))
tk.MustExec(`replace into replace_test_3 set c2=NULL;`)
tk.MustExec(`replace into replace_test_3 set c2=NULL;`)
require.Equal(t, int64(1), int64(tk.Session().AffectedRows()))
for i := 0; i < 100; i++ {
sql := fmt.Sprintf("replace into replace_test_3 set c2=%d;", i)
tk.MustExec(sql)
}
result := tk.MustQuery("select count(*) from replace_test_3")
result.Check(testkit.Rows("102"))
replaceUniqueIndexSQL = `create table replace_test_4 (c1 int, c2 int, c3 int, UNIQUE INDEX (c1, c2)) partition by hash(c1) partitions 8;`
tk.MustExec(`drop table if exists replace_test_4`)
tk.MustExec(replaceUniqueIndexSQL)
replaceUniqueIndexSQL = `replace into replace_test_4 set c2=NULL;`
tk.MustExec(replaceUniqueIndexSQL)
replaceUniqueIndexSQL = `replace into replace_test_4 set c2=NULL;`
tk.MustExec(replaceUniqueIndexSQL)
require.Equal(t, int64(1), int64(tk.Session().AffectedRows()))
replacePrimaryKeySQL := `create table replace_test_5 (c1 int, c2 int, c3 int, PRIMARY KEY (c1, c2)) partition by hash (c2) partitions 9;`
tk.MustExec(replacePrimaryKeySQL)
replacePrimaryKeySQL = `replace into replace_test_5 set c1=1, c2=2;`
tk.MustExec(replacePrimaryKeySQL)
replacePrimaryKeySQL = `replace into replace_test_5 set c1=1, c2=2;`
tk.MustExec(replacePrimaryKeySQL)
require.Equal(t, int64(1), int64(tk.Session().AffectedRows()))
issue989SQL := `CREATE TABLE tIssue989 (a int, b int, KEY(a), UNIQUE KEY(b)) partition by hash (b) partitions 10;`
tk.MustExec(issue989SQL)
issue989SQL = `insert into tIssue989 (a, b) values (1, 2);`
tk.MustExec(issue989SQL)
issue989SQL = `replace into tIssue989(a, b) values (111, 2);`
tk.MustExec(issue989SQL)
r := tk.MustQuery("select * from tIssue989;")
r.Check(testkit.Rows("111 2"))
}
func TestPartitionedTableUpdate(t *testing.T) {
failpoint.Enable("github.com/pingcap/tidb/planner/core/forceDynamicPrune", `return(true)`)
defer failpoint.Disable("github.com/pingcap/tidb/planner/core/forceDynamicPrune")
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 int not null default 1, name varchar(255))
PARTITION BY RANGE ( id ) (
PARTITION p0 VALUES LESS THAN (6),
PARTITION p1 VALUES LESS THAN (11),
PARTITION p2 VALUES LESS THAN (16),
PARTITION p3 VALUES LESS THAN (21))`)
tk.MustExec(`insert INTO t VALUES (1, "hello");`)
tk.CheckExecResult(1, 0)
tk.MustExec(`insert INTO t VALUES (7, "hello");`)
tk.CheckExecResult(1, 0)
// update non partition column
tk.MustExec(`UPDATE t SET name = "abc" where id > 0;`)
tk.CheckExecResult(2, 0)
require.Equal(t, tk.Session().LastMessage(), "Rows matched: 2 Changed: 2 Warnings: 0")
r := tk.MustQuery(`SELECT * from t order by id limit 2;`)
r.Check(testkit.Rows("1 abc", "7 abc"))
// update partition column
tk.MustExec(`update t set id = id + 1`)
tk.CheckExecResult(2, 0)
require.Equal(t, tk.Session().LastMessage(), "Rows matched: 2 Changed: 2 Warnings: 0")
r = tk.MustQuery(`SELECT * from t order by id limit 2;`)
r.Check(testkit.Rows("2 abc", "8 abc"))
// update partition column, old and new record locates on different partitions
tk.MustExec(`update t set id = 20 where id = 8`)
tk.CheckExecResult(1, 0)
require.Equal(t, tk.Session().LastMessage(), "Rows matched: 1 Changed: 1 Warnings: 0")
r = tk.MustQuery(`SELECT * from t order by id limit 2;`)
r.Check(testkit.Rows("2 abc", "20 abc"))
// table option is auto-increment
tk.MustExec("drop table if exists t;")
tk.MustExec(`create table t (id int not null auto_increment, name varchar(255), primary key(id))
PARTITION BY RANGE ( id ) (
PARTITION p0 VALUES LESS THAN (6),
PARTITION p1 VALUES LESS THAN (11),
PARTITION p2 VALUES LESS THAN (16),
PARTITION p3 VALUES LESS THAN (21))`)
tk.MustExec("insert into t(name) values ('aa')")
tk.MustExec("update t set id = 8 where name = 'aa'")
require.Equal(t, tk.Session().LastMessage(), "Rows matched: 1 Changed: 1 Warnings: 0")
tk.MustExec("insert into t(name) values ('bb')")
r = tk.MustQuery("select * from t;")
r.Check(testkit.Rows("8 aa", "9 bb"))
err := tk.ExecToErr("update t set id = null where name = 'aa'")
require.EqualError(t, err, "[table:1048]Column 'id' cannot be null")
// Test that in a transaction, when a constraint failed in an update statement, the record is not inserted.
tk.MustExec("drop table if exists t;")
tk.MustExec(`create table t (id int, name int unique)
PARTITION BY RANGE ( name ) (
PARTITION p0 VALUES LESS THAN (6),
PARTITION p1 VALUES LESS THAN (11),
PARTITION p2 VALUES LESS THAN (16),
PARTITION p3 VALUES LESS THAN (21))`)
tk.MustExec("insert t values (1, 1), (2, 2);")
err = tk.ExecToErr("update t set name = 1 where id = 2")
require.Error(t, err)
tk.MustQuery("select * from t").Check(testkit.Rows("1 1", "2 2"))
// test update ignore for pimary key
tk.MustExec("drop table if exists t;")
tk.MustExec(`create table t(a bigint, primary key (a))
PARTITION BY RANGE (a) (
PARTITION p0 VALUES LESS THAN (6),
PARTITION p1 VALUES LESS THAN (11))`)
tk.MustExec("insert into t values (5)")
tk.MustExec("insert into t values (7)")
err = tk.ExecToErr("update ignore t set a = 5 where a = 7;")
require.NoError(t, err)
require.Equal(t, tk.Session().LastMessage(), "Rows matched: 1 Changed: 0 Warnings: 1")
r = tk.MustQuery("SHOW WARNINGS;")
r.Check(testkit.Rows("Warning 1062 Duplicate entry '5' for key 't.PRIMARY'"))
tk.MustQuery("select * from t order by a").Check(testkit.Rows("5", "7"))
// test update ignore for truncate as warning
err = tk.ExecToErr("update ignore t set a = 1 where a = (select '2a')")
require.NoError(t, err)
r = tk.MustQuery("SHOW WARNINGS;")
r.Check(testkit.Rows("Warning 1292 Truncated incorrect DOUBLE value: '2a'", "Warning 1292 Truncated incorrect DOUBLE value: '2a'"))
// test update ignore for unique key
tk.MustExec("drop table if exists t;")
tk.MustExec(`create table t(a bigint, unique key I_uniq (a))
PARTITION BY RANGE (a) (
PARTITION p0 VALUES LESS THAN (6),
PARTITION p1 VALUES LESS THAN (11))`)
tk.MustExec("insert into t values (5)")
tk.MustExec("insert into t values (7)")
err = tk.ExecToErr("update ignore t set a = 5 where a = 7;")
require.NoError(t, err)
require.Equal(t, tk.Session().LastMessage(), "Rows matched: 1 Changed: 0 Warnings: 1")
r = tk.MustQuery("SHOW WARNINGS;")
r.Check(testkit.Rows("Warning 1062 Duplicate entry '5' for key 't.I_uniq'"))
tk.MustQuery("select * from t order by a").Check(testkit.Rows("5", "7"))
}
func TestPartitionedTableDelete(t *testing.T) {
failpoint.Enable("github.com/pingcap/tidb/planner/core/forceDynamicPrune", `return(true)`)
defer failpoint.Disable("github.com/pingcap/tidb/planner/core/forceDynamicPrune")
createTable := `CREATE TABLE test.t (id int not null default 1, name varchar(255), index(id))
PARTITION BY RANGE ( id ) (
PARTITION p0 VALUES LESS THAN (6),
PARTITION p1 VALUES LESS THAN (11),
PARTITION p2 VALUES LESS THAN (16),
PARTITION p3 VALUES LESS THAN (21))`
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec(createTable)
for i := 1; i < 21; i++ {
tk.MustExec(fmt.Sprintf(`insert into t values (%d, "hello")`, i))
}
tk.MustExec(`delete from t where id = 2 limit 1;`)
tk.CheckExecResult(1, 0)
// Test delete with false condition
tk.MustExec(`delete from t where 0;`)
tk.CheckExecResult(0, 0)
tk.MustExec("insert into t values (2, 'abc')")
tk.MustExec(`delete from t where t.id = 2 limit 1`)
tk.CheckExecResult(1, 0)
// Test delete ignore
tk.MustExec("insert into t values (2, 'abc')")
err := tk.ExecToErr("delete from t where id = (select '2a')")
require.Error(t, err)
err = tk.ExecToErr("delete ignore from t where id = (select '2a')")
require.NoError(t, err)
tk.CheckExecResult(1, 0)
r := tk.MustQuery("SHOW WARNINGS;")
r.Check(testkit.Rows("Warning 1292 Truncated incorrect DOUBLE value: '2a'", "Warning 1292 Truncated incorrect DOUBLE value: '2a'"))
// Test delete without using index, involve multiple partitions.
tk.MustExec("delete from t ignore index(id) where id >= 13 and id <= 17")
tk.CheckExecResult(5, 0)
tk.MustExec("admin check table t")
tk.MustExec(`delete from t;`)
tk.CheckExecResult(14, 0)
// Fix that partitioned table should not use PointGetPlan.
tk.MustExec(`create table t1 (c1 bigint, c2 bigint, c3 bigint, primary key(c1)) partition by range (c1) (partition p0 values less than (3440))`)
tk.MustExec("insert into t1 values (379, 379, 379)")
tk.MustExec("delete from t1 where c1 = 379")
tk.CheckExecResult(1, 0)
tk.MustExec(`drop table t1;`)
}
func TestPartitionOnMissing(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("create schema OnMissing")
tk.MustExec("use OnMissing")
tk.MustExec(`set global tidb_partition_prune_mode='dynamic'`)
tk.MustExec(`set session tidb_partition_prune_mode='dynamic'`)
tk.MustExec(`CREATE TABLE tt1 (
id INT NOT NULL,
listid INT,
name varchar(10)
)
PARTITION BY LIST (listid) (
PARTITION p1 VALUES IN (1),
PARTITION p2 VALUES IN (2),
PARTITION p3 VALUES IN (3),
PARTITION p4 VALUES IN (4)
)`)
tk.MustExec(`CREATE TABLE tt2 (
id INT NOT NULL,
listid INT
)`)
tk.MustExec(`create index idx_listid on tt1(id,listid)`)
tk.MustExec(`create index idx_listid on tt2(listid)`)
tk.MustExec(`insert into tt1 values(1,1,1)`)
tk.MustExec(`insert into tt1 values(2,2,2)`)
tk.MustExec(`insert into tt1 values(3,3,3)`)
tk.MustExec(`insert into tt1 values(4,4,4)`)
tk.MustExec(`insert into tt2 values(1,1)`)
tk.MustExec(`insert into tt2 values(2,2)`)
tk.MustExec(`insert into tt2 values(3,3)`)
tk.MustExec(`insert into tt2 values(4,4)`)
tk.MustExec(`insert into tt2 values(5,5)`)
tk.MustExec(`analyze table tt1`)
tk.MustExec(`analyze table tt2`)
tk.MustQuery(`select /*+ inl_join(tt1)*/ count(*) from tt2
left join tt1 on tt1.listid=tt2.listid and tt1.id=tt2.id`).Check(testkit.Rows("5"))
}