Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ddl: support alter table .. truncate partition #8624

Merged
merged 12 commits into from
Dec 11, 2018
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,3 @@ before_install:
script:
- make dev
- ./hack/check-tidy.sh
- ./hack/check_parser_replace.sh
56 changes: 56 additions & 0 deletions ddl/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3056,6 +3056,62 @@ func (s *testDBSuite) TestAlterTableDropPartition(c *C) {
s.testErrorCode(c, sql4, tmysql.ErrDropPartitionNonExistent)
}

func (s *testDBSuite) TestAlterTableTruncatePartition(c *C) {
s.tk = testkit.NewTestKit(c, s.store)
s.tk.MustExec("use test")
s.tk.MustExec("drop table if exists employees")
s.tk.MustExec("set @@tidb_enable_table_partition = 1")
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("insert into employees values (1, 1990)")
s.tk.MustExec("insert into employees values (2, 1995)")
s.tk.MustExec("insert into employees values (3, 2000)")
result := s.tk.MustQuery("select * from employees order by id")
result.Check(testkit.Rows(`1 1990`, `2 1995`, `3 2000`))

s.testErrorCode(c, "alter table employees truncate partition xxx", tmysql.ErrUnknownPartition)

ctx := s.tk.Se.(sessionctx.Context)
is := domain.GetDomain(ctx).InfoSchema()
oldTblInfo, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("employees"))
c.Assert(err, IsNil)
oldPID := oldTblInfo.Meta().Partition.Definitions[0].ID

s.tk.MustExec("alter table employees truncate partition p1")
result = s.tk.MustQuery("select * from employees order by id")
result.Check(testkit.Rows(`2 1995`, `3 2000`))

partitionPrefix := tablecodec.EncodeTablePrefix(oldPID)
hasOldPartitionData := checkPartitionDelRangeDone(c, s, partitionPrefix)
c.Assert(hasOldPartitionData, IsFalse)

is = domain.GetDomain(ctx).InfoSchema()
oldTblInfo, err = is.TableByName(model.NewCIStr("test"), model.NewCIStr("employees"))
c.Assert(err, IsNil)
newPID := oldTblInfo.Meta().Partition.Definitions[0].ID
c.Assert(oldPID != newPID, IsTrue)

s.tk.MustExec("alter table employees truncate partition p3")
result = s.tk.MustQuery("select * from employees")
result.Check(testkit.Rows(`2 1995`))

crazycs520 marked this conversation as resolved.
Show resolved Hide resolved
s.tk.MustExec("insert into employees values (1, 1984)")
crazycs520 marked this conversation as resolved.
Show resolved Hide resolved
result = s.tk.MustQuery("select * from employees order by id")
result.Check(testkit.Rows(`1 1984`, `2 1995`))
s.tk.MustExec("insert into employees values (3, 2000)")
result = s.tk.MustQuery("select * from employees order by id")
result.Check(testkit.Rows(`1 1984`, `2 1995`, `3 2000`))

s.tk.MustExec(`create table non_partition (id int)`)
s.testErrorCode(c, "alter table non_partition truncate partition p0", tmysql.ErrPartitionMgmtOnNonpartitioned)
}

func (s *testDBSuite) TestAddPartitionTooManyPartitions(c *C) {
s.tk = testkit.NewTestKit(c, s.store)
s.tk.MustExec("use test")
Expand Down
3 changes: 3 additions & 0 deletions ddl/ddl.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ var (
errWaitReorgTimeout = terror.ClassDDL.New(codeWaitReorgTimeout, "wait for reorganization timeout")
errInvalidStoreVer = terror.ClassDDL.New(codeInvalidStoreVer, "invalid storage current version")

errUnknownPartition = terror.ClassDDL.New(codeUnknownPartition, mysql.MySQLErrName[mysql.ErrUnknownPartition])
// We don't support dropping column with index covered now.
errCantDropColWithIndex = terror.ClassDDL.New(codeCantDropColWithIndex, "can't drop column with index")
errUnsupportedAddColumn = terror.ClassDDL.New(codeUnsupportedAddColumn, "unsupported add column")
Expand Down Expand Up @@ -636,6 +637,7 @@ const (
codeWrongExprInPartitionFunc = terror.ErrCode(mysql.ErrWrongExprInPartitionFunc)
codeWarnDataTruncated = terror.ErrCode(mysql.WarnDataTruncated)
codeCoalesceOnlyOnHashPartition = terror.ErrCode(mysql.ErrCoalesceOnlyOnHashPartition)
codeUnknownPartition = terror.ErrCode(mysql.ErrUnknownPartition)
)

func init() {
Expand Down Expand Up @@ -685,6 +687,7 @@ func init() {
codeWrongExprInPartitionFunc: mysql.ErrWrongExprInPartitionFunc,
codeWarnDataTruncated: mysql.WarnDataTruncated,
codeCoalesceOnlyOnHashPartition: mysql.ErrCoalesceOnlyOnHashPartition,
codeUnknownPartition: mysql.ErrUnknownPartition,
}
terror.ErrClassToMySQLCodes[terror.ClassDDL] = ddlMySQLErrCodes
}
39 changes: 39 additions & 0 deletions ddl/ddl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,8 @@ func (d *ddl) AlterTable(ctx sessionctx.Context, ident ast.Ident, specs []*ast.A
err = d.DropIndex(ctx, ident, model.NewCIStr(spec.Name))
case ast.AlterTableDropPartition:
err = d.DropTablePartition(ctx, ident, spec)
case ast.AlterTableTruncatePartition:
err = d.TruncateTablePartition(ctx, ident, spec)
case ast.AlterTableAddConstraint:
constr := spec.Constraint
switch spec.Constraint.Tp {
Expand Down Expand Up @@ -1470,6 +1472,43 @@ func (d *ddl) CoalescePartitions(ctx sessionctx.Context, ident ast.Ident, spec *
return errors.Trace(err)
}

func (d *ddl) TruncateTablePartition(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.GenWithStackByArgs(schema))
}
t, err := is.TableByName(ident.Schema, ident.Name)
if err != nil {
return errors.Trace(infoschema.ErrTableNotExists.GenWithStackByArgs(ident.Schema, ident.Name))
}
meta := t.Meta()
if meta.GetPartitionInfo() == nil {
return errors.Trace(ErrPartitionMgmtOnNonpartitioned)
}

var pid int64
pid, err = findPartitionByName(meta, spec.Name)
if err != nil {
return errors.Trace(err)
}

job := &model.Job{
SchemaID: schema.ID,
TableID: meta.ID,
Type: model.ActionTruncateTablePartition,
BinlogInfo: &model.HistoryInfo{},
Args: []interface{}{pid},
}

err = d.doDDLJob(ctx, job)
if err != nil {
return errors.Trace(err)
}
err = d.callHookOnChanged(err)
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)
Expand Down
4 changes: 3 additions & 1 deletion ddl/ddl_worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,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, model.ActionDropTablePartition:
case model.ActionDropSchema, model.ActionDropTable, model.ActionTruncateTable, model.ActionDropIndex, model.ActionDropTablePartition, model.ActionTruncateTablePartition:
ciscoxll marked this conversation as resolved.
Show resolved Hide resolved
err = w.deleteRange(job)
}
if err != nil {
Expand Down Expand Up @@ -472,6 +472,8 @@ func (w *worker) runDDLJob(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64,
ver, err = onDropTable(t, job)
case model.ActionDropTablePartition:
ver, err = onDropTablePartition(t, job)
case model.ActionTruncateTablePartition:
ver, err = onTruncateTablePartition(t, job)
case model.ActionAddColumn:
ver, err = onAddColumn(d, t, job)
case model.ActionDropColumn:
Expand Down
2 changes: 1 addition & 1 deletion ddl/delete_range.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ 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:
case model.ActionDropTablePartition, model.ActionTruncateTablePartition:
var physicalTableID int64
if err := job.DecodeArgs(&physicalTableID); err != nil {
return errors.Trace(err)
Expand Down
58 changes: 58 additions & 0 deletions ddl/partition.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,18 @@ func checkDropTablePartition(meta *model.TableInfo, partName string) error {
return errors.Trace(ErrDropPartitionNonExistent.GenWithStackByArgs(partName))
}

func findPartitionByName(meta *model.TableInfo, parName string) (int64, error) {
// TODO: MySQL behavior for hash partition is weird, "create table .. partition by hash partition 4",
// it use p0, p1, p2, p3 as partition names automatically.
parName = strings.ToLower(parName)
for _, def := range meta.Partition.Definitions {
if strings.EqualFold(def.Name.L, parName) {
return def.ID, nil
}
}
return -1, errors.Trace(errUnknownPartition.GenWithStackByArgs(parName, meta.Name.O))
}

// removePartitionInfo each ddl job deletes a partition.
func removePartitionInfo(tblInfo *model.TableInfo, partName string) int64 {
oldDefs := tblInfo.Partition.Definitions
Expand Down Expand Up @@ -365,6 +377,52 @@ func onDropTablePartition(t *meta.Meta, job *model.Job) (ver int64, _ error) {
return ver, nil
}

// onDropTablePartition truncates old partition meta.
func onTruncateTablePartition(t *meta.Meta, job *model.Job) (int64, error) {
var ver int64
var oldID int64
if err := job.DecodeArgs(&oldID); 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)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check if tblInfo == nil.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if tblInfo == nil, err will not be nil.

		return nil, errors.Trace(infoschema.ErrTableNotExists.GenWithStackByArgs(
			fmt.Sprintf("(Schema ID %d)", schemaID),
			fmt.Sprintf("(Table ID %d)", tableID),
		))

See here:

job.State = model.JobStateCancelled

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, sorry, my mistake.

pi := tblInfo.GetPartitionInfo()
if pi == nil {
return ver, errors.Trace(ErrPartitionMgmtOnNonpartitioned)
}

var find bool
for i := 0; i < len(pi.Definitions); i++ {
def := &pi.Definitions[i]
if def.ID == oldID {
pid, err1 := t.GenGlobalID()
if err != nil {
return ver, errors.Trace(err1)
}
def.ID = pid
find = true
break
}
}
if !find {
return ver, errUnknownPartition.GenWithStackByArgs("drop?", tblInfo.Name.O)
crazycs520 marked this conversation as resolved.
Show resolved Hide resolved
}

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.
crazycs520 marked this conversation as resolved.
Show resolved Hide resolved
job.Args = []interface{}{oldID}
return ver, nil
}

func checkAddPartitionTooManyPartitions(piDefs uint64) error {
if piDefs > uint64(PartitionCountLimit) {
return ErrTooManyPartitions
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ require (
github.com/pingcap/errors v0.11.0
github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e
github.com/pingcap/kvproto v0.0.0-20181105061835-1b5d69cd1d26
github.com/pingcap/parser v0.0.0-20181210061630-27e9d3e251d4
github.com/pingcap/parser v0.0.0-20181211024540-4e6d047fcaae
github.com/pingcap/pd v2.1.0-rc.4+incompatible
github.com/pingcap/tidb-tools v0.0.0-20181112132202-4860a0d5de03
github.com/pingcap/tipb v0.0.0-20181012112600-11e33c750323
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e h1:P73/4dPCL96rG
github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw=
github.com/pingcap/kvproto v0.0.0-20181105061835-1b5d69cd1d26 h1:JK4VLNYbSn36QSbCnqALi2ySXdH0DfcMssT/zmLf4Ls=
github.com/pingcap/kvproto v0.0.0-20181105061835-1b5d69cd1d26/go.mod h1:0gwbe1F2iBIjuQ9AH0DbQhL+Dpr5GofU8fgYyXk+ykk=
github.com/pingcap/parser v0.0.0-20181210061630-27e9d3e251d4 h1:2rCHDk4h8VZw0fiC2CFJffOlXU3iMuz1kOt5wTMCemY=
github.com/pingcap/parser v0.0.0-20181210061630-27e9d3e251d4/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA=
github.com/pingcap/parser v0.0.0-20181211024540-4e6d047fcaae h1:RD98+89F/yakFLnztEL4Pi9f+RkOAm2vgRJcB1p6tTw=
github.com/pingcap/parser v0.0.0-20181211024540-4e6d047fcaae/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA=
github.com/pingcap/pd v2.1.0-rc.4+incompatible h1:/buwGk04aHO5odk/+O8ZOXGs4qkUjYTJ2UpCJXna8NE=
github.com/pingcap/pd v2.1.0-rc.4+incompatible/go.mod h1:nD3+EoYes4+aNNODO99ES59V83MZSI+dFbhyr667a0E=
github.com/pingcap/tidb-tools v0.0.0-20181112132202-4860a0d5de03 h1:xVuo5U+l6XAWHsb+xhkZ8zz3jerIwDfCHAO6kR2Kaog=
Expand Down