diff --git a/ast/ddl.go b/ast/ddl.go index 21668716708b9..340027e881c6f 100644 --- a/ast/ddl.go +++ b/ast/ddl.go @@ -741,6 +741,7 @@ const ( AlterTableRenameIndex AlterTableForce AlterTableAddPartitions + AlterTableDropPartition // TODO: Add more actions ) @@ -877,7 +878,7 @@ func (n *TruncateTableStmt) Accept(v Visitor) (Node, bool) { // PartitionDefinition defines a single partition. type PartitionDefinition struct { - Name string + Name model.CIStr LessThan []ExprNode MaxValue bool Comment string diff --git a/ddl/db_test.go b/ddl/db_test.go index 3beab73441a49..610f61ffdc5f0 100644 --- a/ddl/db_test.go +++ b/ddl/db_test.go @@ -1570,11 +1570,11 @@ func (s *testDBSuite) TestCreateTableWithPartition(c *C) { } c.Assert(part.Definitions, HasLen, 3) c.Assert(part.Definitions[0].LessThan[0], Equals, "10") - c.Assert(part.Definitions[0].Name, Equals, "p0") + c.Assert(part.Definitions[0].Name.L, Equals, "p0") c.Assert(part.Definitions[1].LessThan[0], Equals, "20") - c.Assert(part.Definitions[1].Name, Equals, "p1") + c.Assert(part.Definitions[1].Name.L, Equals, "p1") c.Assert(part.Definitions[2].LessThan[0], Equals, "MAXVALUE") - c.Assert(part.Definitions[2].Name, Equals, "p2") + c.Assert(part.Definitions[2].Name.L, Equals, "p2") s.tk.MustExec("drop table if exists employees;") sql1 := `create table employees ( @@ -2392,8 +2392,10 @@ func (s *testDBSuite) TestBackwardCompatibility(c *C) { } func (s *testDBSuite) TestAlterTableAddPartition(c *C) { - s.tk.MustExec("use test") - s.tk.MustExec("drop table if employees") + s.tk = testkit.NewTestKit(c, s.store) + s.tk.MustExec("use test;") + s.tk.MustExec("set @@session.tidb_enable_table_partition=1") + s.tk.MustExec("drop table if exists employees;") s.tk.MustExec(`create table employees ( id int not null, hired date not null @@ -2405,43 +2407,44 @@ func (s *testDBSuite) TestAlterTableAddPartition(c *C) { );`) s.tk.MustExec(`alter table employees add partition ( partition p4 values less than (2010), - partition p5 values less than maxvalue + partition p5 values less than MAXVALUE );`) ctx := s.tk.Se.(sessionctx.Context) is := domain.GetDomain(ctx).InfoSchema() - tbl, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("tp")) + tbl, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("employees")) 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, "`hired`") + c.Assert(part.Expr, Equals, "year(`hired`)") c.Assert(part.Definitions, HasLen, 5) c.Assert(part.Definitions[0].LessThan[0], Equals, "1991") - c.Assert(part.Definitions[0].Name, Equals, "p1") + c.Assert(part.Definitions[0].Name, Equals, model.NewCIStr("p1")) c.Assert(part.Definitions[1].LessThan[0], Equals, "1996") - c.Assert(part.Definitions[1].Name, Equals, "p2") + c.Assert(part.Definitions[1].Name, Equals, model.NewCIStr("p2")) c.Assert(part.Definitions[2].LessThan[0], Equals, "2001") - c.Assert(part.Definitions[2].Name, Equals, "p3") + c.Assert(part.Definitions[2].Name, Equals, model.NewCIStr("p3")) c.Assert(part.Definitions[3].LessThan[0], Equals, "2010") - c.Assert(part.Definitions[3].Name, Equals, "p4") - c.Assert(part.Definitions[4].LessThan[0], Equals, "maxvalue") - c.Assert(part.Definitions[4].Name, Equals, "p5") + c.Assert(part.Definitions[3].Name, Equals, model.NewCIStr("p4")) + c.Assert(part.Definitions[4].LessThan[0], Equals, "MAXVALUE") + c.Assert(part.Definitions[4].Name, Equals, model.NewCIStr("p5")) - s.tk.MustExec("drop table if t1") - s.tk.MustExec("create table t1(a int)") - sql1 := `alter table t1 add partition ( + s.tk.MustExec("drop table if exists table1;") + s.tk.MustExec("create table table1(a int)") + sql1 := `alter table table1 add partition ( partition p1 values less than (2010), partition p2 values less than maxvalue );` - s.testErrorCode(c, sql1, mysql.ErrPartitionMgmtOnNonpartitioned) + s.testErrorCode(c, sql1, tmysql.ErrPartitionMgmtOnNonpartitioned) - sql2 := "alter table t1 add partition" - s.testErrorCode(c, sql2, mysql.ErrPartitionsMustBeDefined) + sql2 := "alter table table1 add partition" + s.testErrorCode(c, sql2, tmysql.ErrPartitionsMustBeDefined) + + s.tk.MustExec("drop table if exists table2;") + s.tk.MustExec(`create table table2 ( - s.tk.MustExec("drop table if t2") - s.tk.MustExec(`create table t2 ( id int not null, hired date not null ) @@ -2450,41 +2453,179 @@ func (s *testDBSuite) TestAlterTableAddPartition(c *C) { partition p2 values less than maxvalue );`) - sql3 := `alter table t2 add partition ( + sql3 := `alter table table2 add partition ( partition p3 values less than (2010) );` - s.testErrorCode(c, sql3, mysql.ErrPartitionMaxvalue) + s.testErrorCode(c, sql3, tmysql.ErrPartitionMaxvalue) - s.tk.MustExec("drop table if t3") - s.tk.MustExec(`create table t3 ( + s.tk.MustExec("drop table if exists table3;") + s.tk.MustExec(`create table table3 ( id int not null, hired date not null ) partition by range( year(hired) ) ( partition p1 values less than (1991), - partition p3 values less than (2001) + partition p2 values less than (2001) );`) - sql4 := `alter table t3 add partition ( + sql4 := `alter table table3 add partition ( partition p3 values less than (1993) );` - s.testErrorCode(c, sql4, mysql.ErrRangeNotIncreasing) + s.testErrorCode(c, sql4, tmysql.ErrRangeNotIncreasing) - sql5 := `alter table t3 add partition ( + sql5 := `alter table table3 add partition ( partition p1 values less than (1993) );` - s.testErrorCode(c, sql5, mysql.ErrSameNamePartition) + s.testErrorCode(c, sql5, tmysql.ErrSameNamePartition) - sql6 := `alter table t3 add partition ( + sql6 := `alter table table3 add partition ( partition p1 values less than (1993), partition p1 values less than (1995) );` - s.testErrorCode(c, sql6, mysql.ErrSameNamePartition) + s.testErrorCode(c, sql6, tmysql.ErrSameNamePartition) - sql7 := `alter table t3 add partition ( + sql7 := `alter table table3 add partition ( partition p4 values less than (1993), - partition p1 values less than (1995), - partition p5 values less than maxvalue, + partition p1 values less than (1995), + partition p5 values less than maxvalue );` - s.testErrorCode(c, sql7, mysql.ErrSameNamePartition) + s.testErrorCode(c, sql7, tmysql.ErrSameNamePartition) +} + +func (s *testDBSuite) TestAlterTableDropPartition(c *C) { + s.tk = testkit.NewTestKit(c, s.store) + s.tk.MustExec("use test") + s.tk.MustExec("set @@session.tidb_enable_table_partition=1") + s.tk.MustExec("drop table if exists employees") + s.tk.MustExec(`create table employees ( + id int not null, + hired int not null + ) + partition by range( hired ) ( + partition p1 values less than (1991), + partition p2 values less than (1996), + partition p3 values less than (2001) + );`) + + s.tk.MustExec("alter table employees drop partition p3;") + ctx := s.tk.Se.(sessionctx.Context) + is := domain.GetDomain(ctx).InfoSchema() + tbl, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("employees")) + c.Assert(err, IsNil) + c.Assert(tbl.Meta().GetPartitionInfo(), NotNil) + part := tbl.Meta().Partition + c.Assert(part.Type, Equals, model.PartitionTypeRange) + c.Assert(part.Expr, Equals, "`hired`") + c.Assert(part.Definitions, HasLen, 2) + c.Assert(part.Definitions[0].LessThan[0], Equals, "1991") + c.Assert(part.Definitions[0].Name, Equals, model.NewCIStr("p1")) + c.Assert(part.Definitions[1].LessThan[0], Equals, "1996") + c.Assert(part.Definitions[1].Name, Equals, model.NewCIStr("p2")) + + s.tk.MustExec("drop table if exists table1;") + s.tk.MustExec("create table table1 (a int);") + sql1 := "alter table table1 drop partition p10;" + s.testErrorCode(c, sql1, tmysql.ErrPartitionMgmtOnNonpartitioned) + + s.tk.MustExec("drop table if exists table2;") + s.tk.MustExec(`create table table2 ( + id int not null, + hired date not null + ) + partition by range( year(hired) ) ( + partition p1 values less than (1991), + partition p2 values less than (1996), + partition p3 values less than (2001) + );`) + sql2 := "alter table table2 drop partition p10;" + s.testErrorCode(c, sql2, tmysql.ErrDropPartitionNonExistent) + + s.tk.MustExec("drop table if exists table3;") + s.tk.MustExec(`create table table3 ( + id int not null + ) + partition by range( id ) ( + partition p1 values less than (1991) + );`) + sql3 := "alter table table3 drop partition p1;" + s.testErrorCode(c, sql3, tmysql.ErrDropLastPartition) + + s.tk.MustExec("drop table if exists table4;") + s.tk.MustExec(`create table table4 ( + id int not null + ) + partition by range( id ) ( + partition p1 values less than (10), + partition p2 values less than (20), + partition p3 values less than MAXVALUE + );`) + + s.tk.MustExec("alter table table4 drop partition p2;") + is = domain.GetDomain(ctx).InfoSchema() + tbl, err = is.TableByName(model.NewCIStr("test"), model.NewCIStr("table4")) + c.Assert(err, IsNil) + c.Assert(tbl.Meta().GetPartitionInfo(), NotNil) + part = tbl.Meta().Partition + c.Assert(part.Type, Equals, model.PartitionTypeRange) + c.Assert(part.Expr, Equals, "`id`") + c.Assert(part.Definitions, HasLen, 2) + c.Assert(part.Definitions[0].LessThan[0], Equals, "10") + c.Assert(part.Definitions[0].Name, Equals, model.NewCIStr("p1")) + c.Assert(part.Definitions[1].LessThan[0], Equals, "MAXVALUE") + c.Assert(part.Definitions[1].Name, Equals, model.NewCIStr("p3")) + + s.tk.MustExec("drop table if exists tr;") + s.tk.MustExec(` create table tr( + id int, name varchar(50), + purchased date + ) + partition by range( year(purchased) ) ( + partition p0 values less than (1990), + partition p1 values less than (1995), + partition p2 values less than (2000), + partition p3 values less than (2005), + partition p4 values less than (2010), + partition p5 values less than (2015) + );`) + s.tk.MustExec(`INSERT INTO tr VALUES + (1, 'desk organiser', '2003-10-15'), + (2, 'alarm clock', '1997-11-05'), + (3, 'chair', '2009-03-10'), + (4, 'bookcase', '1989-01-10'), + (5, 'exercise bike', '2014-05-09'), + (6, 'sofa', '1987-06-05'), + (7, 'espresso maker', '2011-11-22'), + (8, 'aquarium', '1992-08-04'), + (9, 'study desk', '2006-09-16'), + (10, 'lava lamp', '1998-12-25');`) + result := s.tk.MustQuery("select * from tr where purchased between '1995-01-01' and '1999-12-31';") + result.Check(testkit.Rows(`2 alarm clock 1997-11-05`, `10 lava lamp 1998-12-25`)) + s.tk.MustExec("alter table tr drop partition p2;") + result = s.tk.MustQuery("select * from tr where purchased between '1995-01-01' and '1999-12-31';") + result.Check(testkit.Rows()) + + result = s.tk.MustQuery("select * from tr where purchased between '2010-01-01' and '2014-12-31';") + result.Check(testkit.Rows(`5 exercise bike 2014-05-09`, `7 espresso maker 2011-11-22`)) + s.tk.MustExec("alter table tr drop partition p5;") + result = s.tk.MustQuery("select * from tr where purchased between '2010-01-01' and '2014-12-31';") + result.Check(testkit.Rows()) + + s.tk.MustExec("alter table tr drop partition p4;") + result = s.tk.MustQuery("select * from tr where purchased between '2005-01-01' and '2009-12-31';") + result.Check(testkit.Rows()) + + s.tk.MustExec("drop table if exists table4;") + s.tk.MustExec(`create table table4 ( + id int not null + ) + partition by range( id ) ( + partition Par1 values less than (1991), + partition pAR2 values less than (1992), + partition Par3 values less than (1995), + partition PaR5 values less than (1996) + );`) + s.tk.MustExec("alter table table4 drop partition Par2;") + s.tk.MustExec("alter table table4 drop partition PAR5;") + sql4 := "alter table table4 drop partition PAR0;" + s.testErrorCode(c, sql4, tmysql.ErrDropPartitionNonExistent) } diff --git a/ddl/ddl.go b/ddl/ddl.go index 09230bf72771b..8c2fb80c81260 100644 --- a/ddl/ddl.go +++ b/ddl/ddl.go @@ -170,6 +170,8 @@ var ( ErrPartitionMaxvalue = terror.ClassDDL.New(codePartitionMaxvalue, "MAXVALUE can only be used in last partition definition") // ErrTooManyValues returns cannot have more than one value for this type of partitioning. ErrTooManyValues = terror.ClassDDL.New(codeErrTooManyValues, mysql.MySQLErrName[mysql.ErrTooManyValues]) + //ErrDropLastPartition returns cannot remove all partitions, use drop table instead. + ErrDropLastPartition = terror.ClassDDL.New(codeDropLastPartition, mysql.MySQLErrName[mysql.ErrDropLastPartition]) ) // DDL is responsible for updating schema in data store and maintaining in-memory InfoSchema cache. @@ -574,6 +576,7 @@ const ( codeRangeNotIncreasing = terror.ErrCode(mysql.ErrRangeNotIncreasing) codePartitionMaxvalue = terror.ErrCode(mysql.ErrPartitionMaxvalue) codeErrTooManyValues = terror.ErrCode(mysql.ErrTooManyValues) + codeDropLastPartition = terror.ErrCode(mysql.ErrDropLastPartition) ) func init() { @@ -613,6 +616,7 @@ func init() { codeRangeNotIncreasing: mysql.ErrRangeNotIncreasing, codePartitionMaxvalue: mysql.ErrPartitionMaxvalue, codeErrTooManyValues: mysql.ErrTooManyValues, + codeDropLastPartition: mysql.ErrDropLastPartition, } terror.ErrClassToMySQLCodes[terror.ClassDDL] = ddlMySQLErrCodes } diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index 0fc8327ada773..51cd1efb85f50 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -976,6 +976,8 @@ func (d *ddl) AlterTable(ctx sessionctx.Context, ident ast.Ident, specs []*ast.A err = d.DropColumn(ctx, ident, spec.OldColumnName.Name) case ast.AlterTableDropIndex: err = d.DropIndex(ctx, ident, model.NewCIStr(spec.Name)) + case ast.AlterTableDropPartition: + err = d.DropTablePartition(ctx, ident, spec) case ast.AlterTableAddConstraint: constr := spec.Constraint switch spec.Constraint.Tp { @@ -1211,7 +1213,7 @@ func (d *ddl) AddTablePartitions(ctx sessionctx.Context, ident ast.Ident, spec * } meta := t.Meta() - if meta.GetPartitionInfo() == nil && meta.Partition == nil { + if meta.GetPartitionInfo() == nil { return errors.Trace(ErrPartitionMgmtOnNonpartitioned) } partInfo, err := buildPartitionInfo(meta, d, spec) @@ -1242,6 +1244,41 @@ func (d *ddl) AddTablePartitions(ctx sessionctx.Context, ident ast.Ident, spec * return errors.Trace(err) } +func (d *ddl) DropTablePartition(ctx sessionctx.Context, ident ast.Ident, spec *ast.AlterTableSpec) error { + is := d.infoHandle.Get() + schema, ok := is.SchemaByName(ident.Schema) + if !ok { + return errors.Trace(infoschema.ErrDatabaseNotExists.GenByArgs(schema)) + } + t, err := is.TableByName(ident.Schema, ident.Name) + if err != nil { + return errors.Trace(infoschema.ErrTableNotExists.GenByArgs(ident.Schema, ident.Name)) + } + meta := t.Meta() + if meta.GetPartitionInfo() == nil { + return errors.Trace(ErrPartitionMgmtOnNonpartitioned) + } + err = checkDropTablePartition(meta, spec.Name) + if err != nil { + return errors.Trace(err) + } + + job := &model.Job{ + SchemaID: schema.ID, + TableID: meta.ID, + Type: model.ActionDropTablePartition, + BinlogInfo: &model.HistoryInfo{}, + Args: []interface{}{spec.Name}, + } + + err = d.doDDLJob(ctx, job) + if err != nil { + return errors.Trace(err) + } + err = d.callHookOnChanged(err) + return errors.Trace(err) +} + // DropColumn will drop a column from the table, now we don't support drop the column with index covered. func (d *ddl) DropColumn(ctx sessionctx.Context, ti ast.Ident, colName model.CIStr) error { is := d.GetInformationSchema(ctx) diff --git a/ddl/ddl_worker.go b/ddl/ddl_worker.go index 13ee77df39711..51fd0537f5dd7 100644 --- a/ddl/ddl_worker.go +++ b/ddl/ddl_worker.go @@ -264,7 +264,7 @@ func (w *worker) finishDDLJob(t *meta.Meta, job *model.Job) (err error) { } // After rolling back an AddIndex operation, we need to use delete-range to delete the half-done index data. err = w.deleteRange(job) - case model.ActionDropSchema, model.ActionDropTable, model.ActionTruncateTable, model.ActionDropIndex: + case model.ActionDropSchema, model.ActionDropTable, model.ActionTruncateTable, model.ActionDropIndex, model.ActionDropTablePartition: err = w.deleteRange(job) } if err != nil { @@ -419,6 +419,8 @@ func (w *worker) runDDLJob(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, ver, err = onCreateTable(d, t, job) case model.ActionDropTable: ver, err = onDropTable(t, job) + case model.ActionDropTablePartition: + ver, err = onDropTablePartition(t, job) case model.ActionAddColumn: ver, err = onAddColumn(d, t, job) case model.ActionDropColumn: diff --git a/ddl/delete_range.go b/ddl/delete_range.go index b451509875c01..bd97635bf0530 100644 --- a/ddl/delete_range.go +++ b/ddl/delete_range.go @@ -241,6 +241,14 @@ func insertJobIntoDeleteRangeTable(ctx sessionctx.Context, job *model.Job) error startKey := tablecodec.EncodeTablePrefix(tableID) endKey := tablecodec.EncodeTablePrefix(tableID + 1) return doInsert(s, job.ID, tableID, startKey, endKey, now) + case model.ActionDropTablePartition: + var partitionID int64 + if err := job.DecodeArgs(&partitionID); err != nil { + return errors.Trace(err) + } + startKey := tablecodec.EncodeTablePrefix(partitionID) + endKey := tablecodec.EncodeTablePrefix(partitionID + 1) + return doInsert(s, job.ID, partitionID, startKey, endKey, now) // ActionAddIndex needs do it, because it needs to be rolled back when it's canceled. case model.ActionAddIndex: tableID := job.TableID diff --git a/ddl/partition.go b/ddl/partition.go index 571a10df3f15b..5ca3ed31855a4 100644 --- a/ddl/partition.go +++ b/ddl/partition.go @@ -21,6 +21,7 @@ import ( "github.com/juju/errors" "github.com/pingcap/tidb/ast" + "github.com/pingcap/tidb/meta" "github.com/pingcap/tidb/model" "github.com/pingcap/tidb/mysql" "github.com/pingcap/tidb/sessionctx" @@ -98,15 +99,15 @@ func checkPartitionNameUnique(tbInfo *model.TableInfo, pi *model.PartitionInfo) if tbInfo.Partition != nil { oldPars := tbInfo.Partition.Definitions for _, oldPar := range oldPars { - partNames[strings.ToLower(oldPar.Name)] = struct{}{} + partNames[oldPar.Name.L] = struct{}{} } } newPars := pi.Definitions for _, newPar := range newPars { - if _, ok := partNames[strings.ToLower(newPar.Name)]; ok { + if _, ok := partNames[newPar.Name.L]; ok { return ErrSameNamePartition.GenByArgs(newPar.Name) } - partNames[strings.ToLower(newPar.Name)] = struct{}{} + partNames[newPar.Name.L] = struct{}{} } return nil } @@ -154,3 +155,64 @@ func validRangePartitionType(col *table.Column) bool { return false } } + +// checkDropTablePartition checks if the partition exists and does not allow deleting the last existing partition in the table. +func checkDropTablePartition(meta *model.TableInfo, partName string) error { + oldDefs := meta.Partition.Definitions + for _, def := range oldDefs { + if strings.EqualFold(def.Name.L, strings.ToLower(partName)) { + if len(oldDefs) == 1 { + return errors.Trace(ErrDropLastPartition) + } + return nil + } + } + return errors.Trace(ErrDropPartitionNonExistent.GenByArgs(partName)) +} + +// removePartitionInfo each ddl job deletes a partition. +func removePartitionInfo(tblInfo *model.TableInfo, partName string) int64 { + oldDefs := tblInfo.Partition.Definitions + newDefs := make([]model.PartitionDefinition, 0, len(oldDefs)-1) + var pid int64 + for i := 0; i < len(oldDefs); i++ { + if !strings.EqualFold(oldDefs[i].Name.L, strings.ToLower(partName)) { + continue + } + pid = oldDefs[i].ID + newDefs = append(oldDefs[:i], oldDefs[i+1:]...) + break + } + tblInfo.Partition.Definitions = newDefs + return pid +} + +// onDropTablePartition deletes old partition meta. +func onDropTablePartition(t *meta.Meta, job *model.Job) (ver int64, _ error) { + var partName string + if err := job.DecodeArgs(&partName); err != nil { + job.State = model.JobStateCancelled + return ver, errors.Trace(err) + } + tblInfo, err := getTableInfo(t, job, job.SchemaID) + if err != nil { + return ver, errors.Trace(err) + } + // If an error occurs, it returns that it cannot delete all partitions or that the partition doesn't exist. + err = checkDropTablePartition(tblInfo, partName) + if err != nil { + job.State = model.JobStateCancelled + return ver, errors.Trace(err) + } + partitionID := removePartitionInfo(tblInfo, partName) + ver, err = updateVersionAndTableInfo(t, job, tblInfo, true) + if err != nil { + return ver, errors.Trace(err) + } + + // Finish this job. + job.FinishTableJob(model.JobStateDone, model.StateNone, ver, tblInfo) + // A background job will be created to delete old partition data. + job.Args = []interface{}{partitionID} + return ver, nil +} diff --git a/model/ddl.go b/model/ddl.go index 8e273318af09c..596606fa6b7b9 100644 --- a/model/ddl.go +++ b/model/ddl.go @@ -49,6 +49,7 @@ const ( ActionModifyTableComment ActionType = 17 ActionRenameIndex ActionType = 18 ActionAddTablePartition ActionType = 19 + ActionDropTablePartition ActionType = 20 ) var actionMap = map[ActionType]string{ @@ -71,6 +72,7 @@ var actionMap = map[ActionType]string{ ActionModifyTableComment: "modify table comment", ActionRenameIndex: "rename index", ActionAddTablePartition: "add partition", + ActionDropTablePartition: "drop table partition", } // String return current ddl action in string diff --git a/model/model.go b/model/model.go index d7d9c4f2c9f4b..49ea950705d9a 100644 --- a/model/model.go +++ b/model/model.go @@ -285,7 +285,7 @@ type PartitionInfo struct { // PartitionDefinition defines a single partition. type PartitionDefinition struct { ID int64 `json:"id"` - Name string `json:"name"` + Name CIStr `json:"name"` LessThan []string `json:"less_than"` Comment string `json:"comment,omitempty"` } diff --git a/parser/parser.y b/parser/parser.y index f265283cbe9c2..09635031f318f 100644 --- a/parser/parser.y +++ b/parser/parser.y @@ -979,6 +979,13 @@ AlterTableSpec: { $$ = &ast.AlterTableSpec{Tp: ast.AlterTableDropPrimaryKey} } +| "DROP" "PARTITION" Identifier + { + $$ = &ast.AlterTableSpec{ + Tp: ast.AlterTableDropPartition, + Name: $3, + } + } | "DROP" KeyOrIndex Identifier { $$ = &ast.AlterTableSpec{ @@ -1841,8 +1848,8 @@ PartitionDefinition: "PARTITION" Identifier PartDefValuesOpt PartDefCommentOpt PartDefStorageOpt { partDef := &ast.PartitionDefinition{ - Name: $2, - Comment: $4.(string), + Name: model.NewCIStr($2), + Comment: $4.(string), } switch $3.(type) { case []ast.ExprNode: diff --git a/parser/parser_test.go b/parser/parser_test.go index ab8b842a604c9..17a3404d42964 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -1620,6 +1620,9 @@ func (s *testParserSuite) TestDDL(c *C) { PARTITION P1 VALUES LESS THAN (2010), PARTITION P2 VALUES LESS THAN (2015), PARTITION P3 VALUES LESS THAN MAXVALUE)`, true}, + // For drop table partition statement. + {"alter table t drop partition p1;", true}, + {"alter table t drop partition p2;", true}, {"ALTER TABLE t DISABLE KEYS", true}, {"ALTER TABLE t ENABLE KEYS", true}, {"ALTER TABLE t MODIFY COLUMN a varchar(255)", true}, diff --git a/plan/logical_plan_test.go b/plan/logical_plan_test.go index 5213f6bb92e89..6a0f0133f79bc 100644 --- a/plan/logical_plan_test.go +++ b/plan/logical_plan_test.go @@ -467,27 +467,27 @@ func (s *testPlanSuite) TestTablePartition(c *C) { definitions := []model.PartitionDefinition{ { ID: 41, - Name: "p1", + Name: model.NewCIStr("p1"), LessThan: []string{"16"}, }, { ID: 42, - Name: "p2", + Name: model.NewCIStr("p2"), LessThan: []string{"32"}, }, { ID: 43, - Name: "p3", + Name: model.NewCIStr("p3"), LessThan: []string{"64"}, }, { ID: 44, - Name: "p4", + Name: model.NewCIStr("p4"), LessThan: []string{"128"}, }, { ID: 45, - Name: "p5", + Name: model.NewCIStr("p5"), LessThan: []string{"maxvalue"}, }, } diff --git a/table/tables/tables_test.go b/table/tables/tables_test.go index 5eb81fd25d1cf..37ff75356e91d 100644 --- a/table/tables/tables_test.go +++ b/table/tables/tables_test.go @@ -345,7 +345,7 @@ PARTITION BY RANGE ( id ) ( tb, err := ts.dom.InfoSchema().TableByName(model.NewCIStr("test"), model.NewCIStr("t1")) tbInfo := tb.Meta() p0 := tbInfo.Partition.Definitions[0] - c.Assert(p0.Name, Equals, "p0") + c.Assert(p0.Name, Equals, model.NewCIStr("p0")) c.Assert(ts.se.NewTxn(), IsNil) rid, err := tb.AddRecord(ts.se, types.MakeDatums(1), false)