Skip to content

Commit

Permalink
ddl: Coalesce partition (#42476)
Browse files Browse the repository at this point in the history
close #15002
  • Loading branch information
mjonss authored Apr 17, 2023
1 parent 0c736ce commit 4878ed3
Show file tree
Hide file tree
Showing 6 changed files with 429 additions and 33 deletions.
304 changes: 299 additions & 5 deletions ddl/db_partition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3462,8 +3462,9 @@ func TestPartitionErrorCode(t *testing.T) {
)
partition by hash(store_id)
partitions 4;`)
tk.MustGetDBError("alter table employees add partition partitions 8;", dbterror.ErrUnsupportedAddPartition)
tk.MustGetDBError("alter table employees add partition (partition p5 values less than (42));", dbterror.ErrUnsupportedAddPartition)
tk.MustExec("alter table employees add partition partitions 8")
tk.MustGetDBError("alter table employees add partition (partition pNew values less than (42))", ast.ErrPartitionWrongValues)
tk.MustGetDBError("alter table employees add partition (partition pNew values in (42))", ast.ErrPartitionWrongValues)

// coalesce partition
tk.MustExec(`create table clients (
Expand All @@ -3473,8 +3474,8 @@ func TestPartitionErrorCode(t *testing.T) {
signed date
)
partition by hash( month(signed) )
partitions 12;`)
tk.MustGetDBError("alter table clients coalesce partition 4;", dbterror.ErrUnsupportedCoalescePartition)
partitions 12`)
tk.MustContainErrMsg("alter table clients coalesce partition 12", "[ddl:1508]Cannot remove all partitions, use DROP TABLE instead")

tk.MustExec(`create table t_part (a int key)
partition by range(a) (
Expand Down Expand Up @@ -3505,6 +3506,299 @@ func TestPartitionErrorCode(t *testing.T) {
tk1.MustExec("commit")
}

func TestCoalescePartition(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
// coalesce partition
tk.MustExec(`create schema coalescePart`)
tk.MustExec(`use coalescePart`)
tk.MustExec(`create table t (
id int,
fname varchar(30),
lname varchar(30),
signed date
)
partition by hash( month(signed) )
partitions 12`)
for i := 0; i < 200; i++ {
tk.MustExec(`insert into t values (?, "Joe", "Doe", from_days(738974 + ?))`, i, i*3)
}
tk.MustExec("alter table t coalesce partition 4")
tk.MustQuery(`show create table t`).Check(testkit.Rows("" +
"t CREATE TABLE `t` (\n" +
" `id` int(11) DEFAULT NULL,\n" +
" `fname` varchar(30) DEFAULT NULL,\n" +
" `lname` varchar(30) DEFAULT NULL,\n" +
" `signed` date DEFAULT NULL\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin\n" +
"PARTITION BY HASH (MONTH(`signed`)) PARTITIONS 8"))
tk.MustExec(`analyze table t`)
tk.MustQuery(`select partition_name, table_rows from information_schema.partitions where table_name = 't' and table_schema = 'coalescePart'`).Sort().Check(testkit.Rows(""+
"p0 20",
"p1 30",
"p2 30",
"p3 27",
"p4 31",
"p5 20",
"p6 20",
"p7 22"))
tk.MustQuery("" +
`(select 'p0', count(*) from t partition (p0) UNION` +
` select 'p1', count(*) from t partition (p1) UNION` +
` select 'p2', count(*) from t partition (p2) UNION` +
` select 'p3', count(*) from t partition (p3) UNION` +
` select 'p4', count(*) from t partition (p4) UNION` +
` select 'p5', count(*) from t partition (p5) UNION` +
` select 'p6', count(*) from t partition (p6) UNION` +
` select 'p7', count(*) from t partition (p7)` +
`) ORDER BY 1`).Check(testkit.Rows(""+
"p0 20",
"p1 30",
"p2 30",
"p3 27",
"p4 31",
"p5 20",
"p6 20",
"p7 22"))
tk.MustExec(`drop table t`)
tk.MustExec(`create table t (
id int,
fname varchar(30),
lname varchar(30),
signed date
)
partition by key(signed,fname)
partitions 12`)
for i := 0; i < 200; i++ {
tk.MustExec(`insert into t values (?, "Joe", "Doe", from_days(738974 + ?))`, i, i*3)
}
tk.MustExec("alter table t coalesce partition 4")
tk.MustQuery(`show create table t`).Check(testkit.Rows("" +
"t CREATE TABLE `t` (\n" +
" `id` int(11) DEFAULT NULL,\n" +
" `fname` varchar(30) DEFAULT NULL,\n" +
" `lname` varchar(30) DEFAULT NULL,\n" +
" `signed` date DEFAULT NULL\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin\n" +
"PARTITION BY KEY (`signed`,`fname`) PARTITIONS 8"))
tk.MustExec(`analyze table t`)
tk.MustQuery(`select partition_name, table_rows from information_schema.partitions where table_name = 't' and table_schema = 'coalescePart'`).Sort().Check(testkit.Rows(""+
"p0 26",
"p1 28",
"p2 22",
"p3 24",
"p4 30",
"p5 27",
"p6 22",
"p7 21"))
tk.MustQuery("" +
`(select 'p0', count(*) from t partition (p0) UNION` +
` select 'p1', count(*) from t partition (p1) UNION` +
` select 'p2', count(*) from t partition (p2) UNION` +
` select 'p3', count(*) from t partition (p3) UNION` +
` select 'p4', count(*) from t partition (p4) UNION` +
` select 'p5', count(*) from t partition (p5) UNION` +
` select 'p6', count(*) from t partition (p6) UNION` +
` select 'p7', count(*) from t partition (p7)` +
`) ORDER BY 1`).Check(testkit.Rows(""+
"p0 26",
"p1 28",
"p2 22",
"p3 24",
"p4 30",
"p5 27",
"p6 22",
"p7 21"))
}

func TestAddHashPartition(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
// add partition
tk.MustExec("create database addHash")
tk.MustExec("use addHash")
tk.MustExec(`create table t (
id int not null,
fname varchar(30),
lname varchar(30),
hired date not null default '1970-01-01',
separated date,
job_code int,
store_id int
)
partition by hash(store_id)
partitions 4`)
// TiDB does not support system versioned tables / SYSTEM_TIME
// also the error is slightly wrong with 'VALUES HISTORY'
// instead of just 'HISTORY'
tk.MustContainErrMsg(`alter table t add partition (partition pHist history)`, "[ddl:1480]Only SYSTEM_TIME PARTITIONING can use VALUES HISTORY in partition definition")
tk.MustContainErrMsg(`alter table t add partition (partition pList values in (22))`, "[ddl:1480]Only LIST PARTITIONING can use VALUES IN in partition definition")
tk.MustContainErrMsg(`alter table t add partition (partition pRange values less than (22))`, "[ddl:1480]Only RANGE PARTITIONING can use VALUES LESS THAN in partition definition")
tk.MustExec(`insert into t values (20, "Joe", "Doe", '2020-01-05', null, 1,1), (21, "Jane", "Doe", '2021-07-05', null, 2,1)`)
tk.MustExec("alter table t add partition partitions 8")
tk.MustQuery(`show create table t`).Check(testkit.Rows("" +
"t CREATE TABLE `t` (\n" +
" `id` int(11) NOT NULL,\n" +
" `fname` varchar(30) DEFAULT NULL,\n" +
" `lname` varchar(30) DEFAULT NULL,\n" +
" `hired` date NOT NULL DEFAULT '1970-01-01',\n" +
" `separated` date DEFAULT NULL,\n" +
" `job_code` int(11) DEFAULT NULL,\n" +
" `store_id` int(11) DEFAULT NULL\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin\n" +
"PARTITION BY HASH (`store_id`) PARTITIONS 12"))
tk.MustContainErrMsg(`alter table t coalesce partition 0`,
"[ddl:1515]At least one partition must be coalesced")
tk.MustContainErrMsg(`alter table t coalesce partition 12`,
"[ddl:1508]Cannot remove all partitions, use DROP TABLE instead")
tk.MustExec(`create placement policy tworeplicas followers=1`)
tk.MustExec(`create placement policy threereplicas followers=2`)
tk.MustExec(`create placement policy fourreplicas followers=3`)
tk.MustExec("alter table t add partition (partition pp13 comment 'p13' placement policy tworeplicas, partition pp14 comment 'p14' placement policy threereplicas, partition pp15 comment 'p15' placement policy fourreplicas)")
tk.MustExec(`alter table t add partition partitions 1`)
tk.MustExec(`alter table t coalesce partition 1`)
tk.MustQuery(`show create table t`).Check(testkit.Rows("" +
"t CREATE TABLE `t` (\n" +
" `id` int(11) NOT NULL,\n" +
" `fname` varchar(30) DEFAULT NULL,\n" +
" `lname` varchar(30) DEFAULT NULL,\n" +
" `hired` date NOT NULL DEFAULT '1970-01-01',\n" +
" `separated` date DEFAULT NULL,\n" +
" `job_code` int(11) DEFAULT NULL,\n" +
" `store_id` int(11) DEFAULT NULL\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin\n" +
"PARTITION BY HASH (`store_id`)\n" +
"(PARTITION `p0`,\n" +
" PARTITION `p1`,\n" +
" PARTITION `p2`,\n" +
" PARTITION `p3`,\n" +
" PARTITION `p4`,\n" +
" PARTITION `p5`,\n" +
" PARTITION `p6`,\n" +
" PARTITION `p7`,\n" +
" PARTITION `p8`,\n" +
" PARTITION `p9`,\n" +
" PARTITION `p10`,\n" +
" PARTITION `p11`,\n" +
" PARTITION `pp13` COMMENT 'p13' /*T![placement] PLACEMENT POLICY=`tworeplicas` */,\n" +
" PARTITION `pp14` COMMENT 'p14' /*T![placement] PLACEMENT POLICY=`threereplicas` */,\n" +
" PARTITION `pp15` COMMENT 'p15' /*T![placement] PLACEMENT POLICY=`fourreplicas` */)"))
// MySQL keeps the comments, so we should keep all options connected to the remaining partitions too!
// So once you added any partition option,
// it will never go back to just a number of partitions in MySQL!
tk.MustExec("alter table t coalesce partition 2")
tk.MustQuery(`show create table t`).Check(testkit.Rows("" +
"t CREATE TABLE `t` (\n" +
" `id` int(11) NOT NULL,\n" +
" `fname` varchar(30) DEFAULT NULL,\n" +
" `lname` varchar(30) DEFAULT NULL,\n" +
" `hired` date NOT NULL DEFAULT '1970-01-01',\n" +
" `separated` date DEFAULT NULL,\n" +
" `job_code` int(11) DEFAULT NULL,\n" +
" `store_id` int(11) DEFAULT NULL\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin\n" +
"PARTITION BY HASH (`store_id`)\n" +
"(PARTITION `p0`,\n" +
" PARTITION `p1`,\n" +
" PARTITION `p2`,\n" +
" PARTITION `p3`,\n" +
" PARTITION `p4`,\n" +
" PARTITION `p5`,\n" +
" PARTITION `p6`,\n" +
" PARTITION `p7`,\n" +
" PARTITION `p8`,\n" +
" PARTITION `p9`,\n" +
" PARTITION `p10`,\n" +
" PARTITION `p11`,\n" +
" PARTITION `pp13` COMMENT 'p13' /*T![placement] PLACEMENT POLICY=`tworeplicas` */)"))
// If no extra options, it will go back to just numbers in TiDB:
tk.MustExec("alter table t coalesce partition 1")
tk.MustExec(`alter table t add partition (partition p13 comment 'p13')`)
tk.MustContainErrMsg(`alter table t add partition partitions 1`,
"[ddl:1517]Duplicate partition name p13")
tk.MustExec("alter table t coalesce partition 1")
tk.MustQuery(`show create table t`).Check(testkit.Rows("" +
"t CREATE TABLE `t` (\n" +
" `id` int(11) NOT NULL,\n" +
" `fname` varchar(30) DEFAULT NULL,\n" +
" `lname` varchar(30) DEFAULT NULL,\n" +
" `hired` date NOT NULL DEFAULT '1970-01-01',\n" +
" `separated` date DEFAULT NULL,\n" +
" `job_code` int(11) DEFAULT NULL,\n" +
" `store_id` int(11) DEFAULT NULL\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin\n" +
"PARTITION BY HASH (`store_id`) PARTITIONS 12"))
tk.MustExec(`drop placement policy tworeplicas`)
tk.MustExec(`drop placement policy threereplicas`)
tk.MustExec(`drop placement policy fourreplicas`)
tk.MustExec(`drop table t`)

tk.MustExec(`create table t (
id int not null,
fname varchar(30),
lname varchar(30),
hired date not null default '1970-01-01',
separated date,
job_code int,
store_id int
)
partition by key (hired)
partitions 4`)
tk.MustExec(`insert into t values (20, "Joe", "Doe", '2020-01-05', null, 1,1), (21, "Jane", "Doe", '2021-07-05', null, 2,1)`)
tk.MustExec("alter table t add partition partitions 8")
tk.MustQuery(`show create table t`).Check(testkit.Rows("" +
"t CREATE TABLE `t` (\n" +
" `id` int(11) NOT NULL,\n" +
" `fname` varchar(30) DEFAULT NULL,\n" +
" `lname` varchar(30) DEFAULT NULL,\n" +
" `hired` date NOT NULL DEFAULT '1970-01-01',\n" +
" `separated` date DEFAULT NULL,\n" +
" `job_code` int(11) DEFAULT NULL,\n" +
" `store_id` int(11) DEFAULT NULL\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin\n" +
"PARTITION BY KEY (`hired`) PARTITIONS 12"))
tk.MustExec("alter table t add partition (partition p13)")
tk.MustContainErrMsg(`alter table t add partition partitions 1`,
"[ddl:1517]Duplicate partition name p13")
tk.MustQuery(`show create table t`).Check(testkit.Rows("" +
"t CREATE TABLE `t` (\n" +
" `id` int(11) NOT NULL,\n" +
" `fname` varchar(30) DEFAULT NULL,\n" +
" `lname` varchar(30) DEFAULT NULL,\n" +
" `hired` date NOT NULL DEFAULT '1970-01-01',\n" +
" `separated` date DEFAULT NULL,\n" +
" `job_code` int(11) DEFAULT NULL,\n" +
" `store_id` int(11) DEFAULT NULL\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin\n" +
"PARTITION BY KEY (`hired`)\n" +
"(PARTITION `p0`,\n" +
" PARTITION `p1`,\n" +
" PARTITION `p2`,\n" +
" PARTITION `p3`,\n" +
" PARTITION `p4`,\n" +
" PARTITION `p5`,\n" +
" PARTITION `p6`,\n" +
" PARTITION `p7`,\n" +
" PARTITION `p8`,\n" +
" PARTITION `p9`,\n" +
" PARTITION `p10`,\n" +
" PARTITION `p11`,\n" +
" PARTITION `p13`)"))
// Note: MySQL does not remove all names when coalesce partitions is back to defaults
tk.MustExec("alter table t coalesce partition 2")
tk.MustQuery(`show create table t`).Check(testkit.Rows("" +
"t CREATE TABLE `t` (\n" +
" `id` int(11) NOT NULL,\n" +
" `fname` varchar(30) DEFAULT NULL,\n" +
" `lname` varchar(30) DEFAULT NULL,\n" +
" `hired` date NOT NULL DEFAULT '1970-01-01',\n" +
" `separated` date DEFAULT NULL,\n" +
" `job_code` int(11) DEFAULT NULL,\n" +
" `store_id` int(11) DEFAULT NULL\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin\n" +
"PARTITION BY KEY (`hired`) PARTITIONS 11"))
}

func TestConstAndTimezoneDepent(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
Expand Down Expand Up @@ -4505,7 +4799,7 @@ func TestCreateAndAlterIntervalPartition(t *testing.T) {
require.Equal(t, "[ddl:8200]Unsupported FIRST PARTITION, does not seem like an INTERVAL partitioned table", err.Error())
err = tk.ExecToErr(`ALTER TABLE t LAST PARTITION LESS THAN (10)`)
require.Error(t, err)
require.Equal(t, "[ddl:8200]Unsupported add partitions", err.Error())
require.Equal(t, "[ddl:8200]Unsupported LAST PARTITION of HASH/KEY partitioned table", err.Error())
tk.MustExec(`drop table t`)

tk.MustExec(`create table t (a int, b varchar(255)) partition by list (a) (partition p0 values in (1,2,3), partition p1 values in (22,23,24))`)
Expand Down
Loading

0 comments on commit 4878ed3

Please sign in to comment.