Skip to content

Commit

Permalink
Merge pull request pingcap#26 from crazycs520/range-columns-p
Browse files Browse the repository at this point in the history
ddl: support range multi-columns
  • Loading branch information
crazycs520 authored Oct 14, 2020
2 parents e949d65 + e90babe commit bc113df
Show file tree
Hide file tree
Showing 6 changed files with 335 additions and 62 deletions.
196 changes: 166 additions & 30 deletions ddl/db_partition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,10 @@ func (s *testIntegrationSuite3) TestCreateTableWithPartition(c *C) {
tk.MustExec("set @@tidb_enable_table_partition = 1")
tk.MustExec(`create table t30 (
a int,
b float,
b int,
c varchar(30))
partition by range columns (a, b)
(partition p0 values less than (10, 10.0))`)
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 8200 Unsupported partition type, treat as normal table"))
(partition p0 values less than (10, 10))`)

tk.MustGetErrCode(`create table t31 (a int not null) partition by range( a );`, tmysql.ErrPartitionsMustBeDefined)
tk.MustGetErrCode(`create table t32 (a int not null) partition by range columns( a );`, tmysql.ErrPartitionsMustBeDefined)
Expand Down Expand Up @@ -397,39 +396,36 @@ create table log_message_1 (
"create table t (id text) partition by range columns (id) (partition p0 values less than ('abc'));",
ddl.ErrNotAllowedTypeInPartition,
},
// create as normal table, warning.
// {
// "create table t (a int, b varchar(64)) partition by range columns (a, b) (" +
// "partition p0 values less than (1, 'a')," +
// "partition p1 values less than (1, 'a'))",
// ddl.ErrRangeNotIncreasing,
// },
{
"create table t (a int, b varchar(64)) partition by range columns (a, b) (" +
"partition p0 values less than (1, 'a')," +
"partition p1 values less than (1, 'a'))",
ddl.ErrRangeNotIncreasing,
},
{
"create table t (a int, b varchar(64)) partition by range columns ( b) (" +
"partition p0 values less than ( 'a')," +
"partition p1 values less than ('a'))",
ddl.ErrRangeNotIncreasing,
},
// create as normal table, warning.
// {
// "create table t (a int, b varchar(64)) partition by range columns (a, b) (" +
// "partition p0 values less than (1, 'b')," +
// "partition p1 values less than (1, 'a'))",
// ddl.ErrRangeNotIncreasing,
// },
{
"create table t (a int, b varchar(64)) partition by range columns (a, b) (" +
"partition p0 values less than (1, 'b')," +
"partition p1 values less than (1, 'a'))",
ddl.ErrRangeNotIncreasing,
},
{
"create table t (a int, b varchar(64)) partition by range columns (b) (" +
"partition p0 values less than ('b')," +
"partition p1 values less than ('a'))",
ddl.ErrRangeNotIncreasing,
},
// create as normal table, warning.
// {
// "create table t (a int, b varchar(64)) partition by range columns (a, b) (" +
// "partition p0 values less than (1, maxvalue)," +
// "partition p1 values less than (1, 'a'))",
// ddl.ErrRangeNotIncreasing,
// },
{
"create table t (a int, b varchar(64)) partition by range columns (a, b) (" +
"partition p0 values less than (1, maxvalue)," +
"partition p1 values less than (1, 'a'))",
ddl.ErrRangeNotIncreasing,
},
{
"create table t (a int, b varchar(64)) partition by range columns ( b) (" +
"partition p0 values less than ( maxvalue)," +
Expand All @@ -452,13 +448,72 @@ create table log_message_1 (
))
}

tk.MustExec("create table t1 (a int, b char(3)) partition by range columns (a, b) (" +
"partition p0 values less than (1, 'a')," +
"partition p1 values less than (2, maxvalue))")
validCases := []string{
"create table t (a int, b char(3)) partition by range columns (a, b) (" +
"partition p0 values less than (1, 'a')," +
"partition p1 values less than (2, maxvalue))",

"create table t (a int, b char(3)) partition by range columns (b) (" +
"partition p0 values less than ( 'a')," +
"partition p1 values less than (maxvalue))",

`CREATE TABLE t(
a INT,
b INT,
c CHAR(3),
d INT
)
PARTITION BY RANGE COLUMNS(a,d,c) (
PARTITION p0 VALUES LESS THAN (5,10,'ggg'),
PARTITION p1 VALUES LESS THAN (10,20,'mmm'),
PARTITION p2 VALUES LESS THAN (15,30,'sss'),
PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE,MAXVALUE)
);`,
`CREATE TABLE t (
a INT,
b INT
)
PARTITION BY RANGE COLUMNS(a,b) (
PARTITION p0 VALUES LESS THAN (0,10),
PARTITION p1 VALUES LESS THAN (10,20),
PARTITION p2 VALUES LESS THAN (10,30),
PARTITION p3 VALUES LESS THAN (10,35),
PARTITION p4 VALUES LESS THAN (20,40),
PARTITION p5 VALUES LESS THAN (MAXVALUE,MAXVALUE)
);`,
`CREATE TABLE t (
a INT,
b INT,
c INT
)
PARTITION BY RANGE COLUMNS(a,b,c) (
PARTITION p0 VALUES LESS THAN (0,25,50),
PARTITION p1 VALUES LESS THAN (10,20,100),
PARTITION p2 VALUES LESS THAN (10,30,50),
PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE,MAXVALUE)
);`,
`CREATE TABLE t(
id INT,
hired DATE,
age INT
)
PARTITION BY RANGE COLUMNS (id,hired) (
PARTITION p0 VALUES LESS THAN (100,'1970-01-01'),
PARTITION p1 VALUES LESS THAN (200,'1980-01-01'),
PARTITION p2 VALUES LESS THAN (200,'1990-01-01'),
PARTITION p3 VALUES LESS THAN (MAXVALUE,'1900-01-01')
);`,
}

tk.MustExec("create table t2 (a int, b char(3)) partition by range columns (b) (" +
"partition p0 values less than ( 'a')," +
"partition p1 values less than (maxvalue))")
for _, sql := range validCases {
tk.MustExec("drop table if exists t")
tk.MustExec(sql)
tbl := testGetTableByName(c, s.ctx, "test", "t")
tblInfo := tbl.Meta()
c.Assert(tblInfo.Partition, NotNil)
c.Assert(tblInfo.Partition.Enable, Equals, true)
c.Assert(tblInfo.Partition.Type == model.PartitionTypeRange, IsTrue)
}
}

func (s *testIntegrationSuite1) TestCreateTableWithListPartition(c *C) {
Expand Down Expand Up @@ -832,6 +887,48 @@ func (s *testIntegrationSuite5) TestAlterTableAddPartition(c *C) {
tk.MustGetErrCode(sql, tmysql.ErrWrongTypeColumnValue)
}

func (s *testIntegrationSuite5) TestAlterTableAddPartitionByRangeColumns(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test;")
tk.MustExec("drop table if exists t;")
tk.MustExec(`create table t(
id int not null,
hired date not null
)
partition by range columns ( id,hired ) (
PARTITION p0 VALUES LESS THAN (100,'1970-01-01'),
PARTITION p1 VALUES LESS THAN (200,'1980-01-01'),
PARTITION p2 VALUES LESS THAN (200,'1990-01-01')
);`)
tk.MustExec(`alter table t add partition (
PARTITION p3 VALUES LESS THAN (300,'1980-01-01'),
PARTITION p4 VALUES LESS THAN (MAXVALUE,'1990-01-01')
);`)

ctx := tk.Se.(sessionctx.Context)
is := domain.GetDomain(ctx).InfoSchema()
tbl, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
c.Assert(err, IsNil)
c.Assert(tbl.Meta().Partition, NotNil)
part := tbl.Meta().Partition
c.Assert(part.Type, Equals, model.PartitionTypeRange)

c.Assert(part.Expr, Equals, "")
c.Assert(part.Columns[0].L, Equals, "id")
c.Assert(part.Columns[1].L, Equals, "hired")
c.Assert(part.Definitions, HasLen, 5)
c.Assert(part.Definitions[0].LessThan, DeepEquals, []string{"100", "\"1970-01-01\""})
c.Assert(part.Definitions[0].Name, Equals, model.NewCIStr("p0"))
c.Assert(part.Definitions[1].LessThan, DeepEquals, []string{"200", "\"1980-01-01\""})
c.Assert(part.Definitions[1].Name, Equals, model.NewCIStr("p1"))
c.Assert(part.Definitions[2].LessThan, DeepEquals, []string{"200", "\"1990-01-01\""})
c.Assert(part.Definitions[2].Name, Equals, model.NewCIStr("p2"))
c.Assert(part.Definitions[3].LessThan, DeepEquals, []string{"300", "\"1980-01-01\""})
c.Assert(part.Definitions[3].Name, Equals, model.NewCIStr("p3"))
c.Assert(part.Definitions[4].LessThan, DeepEquals, []string{"MAXVALUE", "\"1990-01-01\""})
c.Assert(part.Definitions[4].Name, Equals, model.NewCIStr("p4"))
}

func (s *testIntegrationSuite5) TestAlterTableAddPartitionByList(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test;")
Expand Down Expand Up @@ -962,6 +1059,45 @@ func (s *testIntegrationSuite5) TestAlterTableAddPartitionByListColumns(c *C) {
}
}

func (s *testIntegrationSuite5) TestAlterTableDropPartitionByRangeColumns(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test;")
tk.MustExec("drop table if exists t;")
tk.MustExec(`create table t(
id int not null,
hired date not null
)
partition by range columns ( id,hired ) (
PARTITION p0 VALUES LESS THAN (100,'1970-01-01'),
PARTITION p1 VALUES LESS THAN (200,'1980-01-01'),
PARTITION p2 VALUES LESS THAN (200,'1990-01-01')
);`)

tk.MustExec(`alter table t drop partition p1`)
ctx := tk.Se.(sessionctx.Context)
is := domain.GetDomain(ctx).InfoSchema()
tbl, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
c.Assert(err, IsNil)
c.Assert(tbl.Meta().Partition, NotNil)
part := tbl.Meta().Partition
c.Assert(part.Type, Equals, model.PartitionTypeRange)

c.Assert(part.Expr, Equals, "")
c.Assert(part.Columns[0].L, Equals, "id")
c.Assert(part.Columns[1].L, Equals, "hired")
c.Assert(part.Definitions, HasLen, 2)
c.Assert(part.Definitions[0].LessThan, DeepEquals, []string{"100", "\"1970-01-01\""})
c.Assert(part.Definitions[0].Name, Equals, model.NewCIStr("p0"))
c.Assert(part.Definitions[1].LessThan, DeepEquals, []string{"200", "\"1990-01-01\""})
c.Assert(part.Definitions[1].Name, Equals, model.NewCIStr("p2"))

sql := "alter table t drop partition p10;"
tk.MustGetErrCode(sql, tmysql.ErrDropPartitionNonExistent)
tk.MustExec(`alter table t drop partition p2`)
sql = "alter table t drop partition p0;"
tk.MustGetErrCode(sql, tmysql.ErrDropLastPartition)
}

func (s *testIntegrationSuite5) TestAlterTableDropPartitionByList(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test;")
Expand Down
15 changes: 1 addition & 14 deletions ddl/partition.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,7 @@ func buildTablePartitionInfo(ctx sessionctx.Context, s *ast.CreateTableStmt) (*m
var enable bool
// When tidb_enable_table_partition is 'on' or 'auto'.
if s.Partition.Tp == model.PartitionTypeRange {
// Partition by range expression is enabled by default.
if s.Partition.ColumnNames == nil {
enable = true
}
// Partition by range columns and just one column.
if len(s.Partition.ColumnNames) == 1 {
enable = true
}
enable = true
}
// Partition by hash is enabled by default.
// Note that linear hash is not enabled.
Expand Down Expand Up @@ -91,11 +84,6 @@ func buildTablePartitionInfo(ctx sessionctx.Context, s *ast.CreateTableStmt) (*m
}
pi.Expr = buf.String()
} else if s.Partition.ColumnNames != nil {
// TODO: Support multiple columns for 'PARTITION BY RANGE COLUMNS'.
if s.Partition.Tp == model.PartitionTypeRange && len(s.Partition.ColumnNames) != 1 {
pi.Enable = false
ctx.GetSessionVars().StmtCtx.AppendWarning(ErrUnsupportedPartitionByRangeColumns)
}
pi.Columns = make([]model.CIStr, 0, len(s.Partition.ColumnNames))
for _, cn := range s.Partition.ColumnNames {
pi.Columns = append(pi.Columns, cn.Name)
Expand Down Expand Up @@ -146,7 +134,6 @@ func buildRangePartitionDefinitions(ctx sessionctx.Context, s *ast.CreateTableSt
}

buf := new(bytes.Buffer)
// Range columns partitions support multi-column partitions.
for _, expr := range def.Clause.(*ast.PartitionDefinitionClauseLessThan).Exprs {
expr.Format(buf)
piDef.LessThan = append(piDef.LessThan, buf.String())
Expand Down
2 changes: 1 addition & 1 deletion executor/infoschema_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ func (e *memtableRetriever) setDataFromPartitions(ctx sessionctx.Context, schema

var partitionDesc string
if table.Partition.Type == model.PartitionTypeRange {
partitionDesc = pi.LessThan[0]
partitionDesc = strings.Join(pi.LessThan, ",")
} else if table.Partition.Type == model.PartitionTypeList {
if len(pi.InValues) > 0 {
if len(pi.InValues[0]) == 1 {
Expand Down
29 changes: 29 additions & 0 deletions executor/show_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,35 @@ func (s *testSuite5) TestShowCreateTable(c *C) {
" PARTITION `p3` VALUES IN (7,8,15,16,NULL)\n"+
")"))

// Test show range multi-columns partition table
tk.MustExec(`DROP TABLE IF EXISTS t`)
tk.MustExec(
`CREATE TABLE t(
a INT,
b INT,
c CHAR(3),
d BIGINT
)
PARTITION BY RANGE COLUMNS(a,d,c) (
PARTITION p0 VALUES LESS THAN (5,10,'ggg'),
PARTITION p1 VALUES LESS THAN (10,20,'mmm'),
PARTITION p2 VALUES LESS THAN (15,30,'sss'),
PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE,MAXVALUE)
);`)
tk.MustQuery(`show create table t`).Check(testutil.RowsWithSep("|",
"t CREATE TABLE `t` (\n"+
" `a` int(11) DEFAULT NULL,\n"+
" `b` int(11) DEFAULT NULL,\n"+
" `c` char(3) DEFAULT NULL,\n"+
" `d` bigint(20) DEFAULT NULL\n"+
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin\n"+
"PARTITION BY RANGE COLUMNS(a,d,c) (\n"+
" PARTITION `p0` VALUES LESS THAN (5,10,\"ggg\"),\n"+
" PARTITION `p1` VALUES LESS THAN (10,20,\"mmm\"),\n"+
" PARTITION `p2` VALUES LESS THAN (15,30,\"sss\"),\n"+
" PARTITION `p3` VALUES LESS THAN (MAXVALUE,MAXVALUE,MAXVALUE)\n"+
")"))

// Test show list partition table
tk.MustExec(`DROP TABLE IF EXISTS t`)
tk.MustExec(`create table t (id int, name varchar(10), unique index idx (id)) partition by list (id) (
Expand Down
65 changes: 65 additions & 0 deletions executor/write_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2893,3 +2893,68 @@ func (s *testSuite4) TestWriteListColumnsPartitionTable(c *C) {
tk.MustExec("delete from t partition (p3,p2)")
tk.MustQuery("select * from t order by id").Check(testkit.Rows("1 a", "2 b"))
}

func (s *testSuite4) TestWritePartitionTableByRangeColumns(c *C) {
tk := testkit.NewTestKitWithInit(c, s.store)
tk.MustExec("use test")
tk.MustExec("set @@session.tidb_enable_table_partition = 1")
tk.MustExec("drop table if exists t")
tk.MustExec(`CREATE TABLE t(
id INT,
hired DATE,
age INT,
unique index idx (id,hired)
)
PARTITION BY RANGE COLUMNS (id,hired) (
PARTITION p0 VALUES LESS THAN (100,'1970-01-01'),
PARTITION p1 VALUES LESS THAN (200,'1980-01-01'),
PARTITION p2 VALUES LESS THAN (200,'1990-01-01'),
PARTITION p3 VALUES LESS THAN (500,'2000-01-01')
);`)

// Test insert,update,delete
tk.MustExec("insert into t values (1, '1960-01-01',20)")
tk.MustExec("update t set age=21 where id=1;")
tk.MustQuery("select * from t").Check(testkit.Rows("1 1960-01-01 21"))
tk.MustQuery("select * from t partition (p0)").Check(testkit.Rows("1 1960-01-01 21"))
tk.MustQuery("select * from t partition (p1,p2,p3)").Check(testkit.Rows())
tk.MustExec("update t set id=101, hired='1980-01-02' where id=1;")
tk.MustQuery("select * from t").Check(testkit.Rows("101 1980-01-02 21"))
tk.MustQuery("select * from t partition (p2)").Check(testkit.Rows("101 1980-01-02 21"))
tk.MustQuery("select * from t partition (p0,p1,p3)").Check(testkit.Rows())
tk.MustExec("replace into t values (101, '1980-01-02',22)")
tk.MustQuery("select * from t").Check(testkit.Rows("101 1980-01-02 22"))
tk.MustQuery("select * from t partition (p2)").Check(testkit.Rows("101 1980-01-02 22"))
tk.MustQuery("select * from t partition (p0,p1,p3)").Check(testkit.Rows())
tk.MustExec("insert into t values (101, '1980-01-02',22) on duplicate key update id=300")
tk.MustQuery("select * from t").Check(testkit.Rows("300 1980-01-02 22"))
tk.MustQuery("select * from t partition (p3)").Check(testkit.Rows("300 1980-01-02 22"))
tk.MustQuery("select * from t partition (p0,p1,p2)").Check(testkit.Rows())
tk.MustExec("delete from t where id=300")
tk.MustQuery("select * from t").Check(testkit.Rows())
tk.MustExec("insert into t values (150, '1960-01-01',20)")
tk.MustExec("delete from t where age=20")
tk.MustQuery("select * from t").Check(testkit.Rows())

// Test insert error
tk.MustExec("insert into t values (1, '1960-01-01',20)")
_, err := tk.Exec("insert into t values (1, '1960-01-01',20)")
c.Assert(err.Error(), Equals, "[kv:1062]Duplicate entry '1-1960-01-01' for key 'idx'")
_, err = tk.Exec("insert into t values (500, '1960-01-01',20)")
c.Assert(err.Error(), Equals, "[table:1526]Table has no partition for value from column_list")
_, err = tk.Exec("insert into t values (250, '2000-01-02',20)")
c.Assert(err.Error(), Equals, "[table:1526]Table has no partition for value from column_list")

// Test drop partition;
tk.MustQuery("select * from t").Check(testkit.Rows("1 1960-01-01 20"))
tk.MustExec("alter table t drop partition p0;")
tk.MustQuery("select * from t").Check(testkit.Rows())

// Test add partition;
_, err = tk.Exec("insert into t values (500, '1960-01-01',20)")
c.Assert(err.Error(), Equals, "[table:1526]Table has no partition for value from column_list")
tk.MustExec("alter table t add partition (partition p4 values less than (600,'2000-01-01'));")
tk.MustExec("insert into t values (500, '1960-01-01',20)")
tk.MustQuery("select * from t").Check(testkit.Rows("500 1960-01-01 20"))
tk.MustExec("admin check table t;")
}
Loading

0 comments on commit bc113df

Please sign in to comment.