Skip to content

Commit b9e035a

Browse files
ddl: error or skip unsupported partition-related DDLs (#10672)
fb7fd47
1 parent 52da1dc commit b9e035a

File tree

7 files changed

+140
-64
lines changed

7 files changed

+140
-64
lines changed

ddl/db_integration_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,17 +1473,17 @@ func (s *testIntegrationSuite3) TestAlterAlgorithm(c *C) {
14731473
s.tk.MustExec("alter table t rename index idx_c to idx_c1, ALGORITHM=DEFAULT")
14741474

14751475
// partition.
1476-
s.assertAlterWarnExec(c, "alter table t truncate partition p1, ALGORITHM=COPY")
1477-
s.assertAlterErrorExec(c, "alter table t truncate partition p2, ALGORITHM=INPLACE")
1478-
s.tk.MustExec("alter table t truncate partition p3, ALGORITHM=INSTANT")
1476+
s.assertAlterWarnExec(c, "alter table t ALGORITHM=COPY, truncate partition p1")
1477+
s.assertAlterErrorExec(c, "alter table t ALGORITHM=INPLACE, truncate partition p2")
1478+
s.tk.MustExec("alter table t ALGORITHM=INSTANT, truncate partition p3")
14791479

14801480
s.assertAlterWarnExec(c, "alter table t add partition (partition p4 values less than (2002)), ALGORITHM=COPY")
14811481
s.assertAlterErrorExec(c, "alter table t add partition (partition p5 values less than (3002)), ALGORITHM=INPLACE")
14821482
s.tk.MustExec("alter table t add partition (partition p6 values less than (4002)), ALGORITHM=INSTANT")
14831483

1484-
s.assertAlterWarnExec(c, "alter table t drop partition p4, ALGORITHM=COPY")
1485-
s.assertAlterErrorExec(c, "alter table t drop partition p5, ALGORITHM=INPLACE")
1486-
s.tk.MustExec("alter table t drop partition p6, ALGORITHM=INSTANT")
1484+
s.assertAlterWarnExec(c, "alter table t ALGORITHM=COPY, drop partition p4")
1485+
s.assertAlterErrorExec(c, "alter table t ALGORITHM=INPLACE, drop partition p5")
1486+
s.tk.MustExec("alter table t ALGORITHM=INSTANT, drop partition p6")
14871487

14881488
// Table options
14891489
s.assertAlterWarnExec(c, "alter table t comment = 'test', ALGORITHM=COPY")

ddl/db_partition_test.go

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
. "github.com/pingcap/check"
2525
"github.com/pingcap/errors"
26+
"github.com/pingcap/parser/ast"
2627
"github.com/pingcap/parser/model"
2728
tmysql "github.com/pingcap/parser/mysql"
2829
"github.com/pingcap/parser/terror"
@@ -324,14 +325,18 @@ create table log_message_1 (
324325
cases := []testCase{
325326
{
326327
"create table t (id int) partition by range columns (id);",
327-
ddl.ErrPartitionsMustBeDefined,
328+
ast.ErrPartitionsMustBeDefined,
328329
},
329330
{
330331
"create table t (id int) partition by range columns (id) (partition p0 values less than (1, 2));",
331-
ddl.ErrPartitionColumnList,
332+
ast.ErrPartitionColumnList,
332333
},
333334
{
334335
"create table t (a int) partition by range columns (b) (partition p0 values less than (1, 2));",
336+
ast.ErrPartitionColumnList,
337+
},
338+
{
339+
"create table t (a int) partition by range columns (b) (partition p0 values less than (1));",
335340
ddl.ErrFieldNotFoundPart,
336341
},
337342
{
@@ -371,7 +376,10 @@ create table log_message_1 (
371376
}
372377
for i, t := range cases {
373378
_, err := tk.Exec(t.sql)
374-
c.Assert(t.err.Equal(err), IsTrue, Commentf("case %d fail, sql = %s", i, t.sql))
379+
c.Assert(t.err.Equal(err), IsTrue, Commentf(
380+
"case %d fail, sql = `%s`\nexpected error = `%v`\n actual error = `%v`",
381+
i, t.sql, t.err, err,
382+
))
375383
}
376384

377385
tk.MustExec("create table t1 (a int, b char(3)) partition by range columns (a, b) (" +
@@ -495,6 +503,15 @@ func (s *testIntegrationSuite5) TestAlterTableAddPartition(c *C) {
495503
partition p5 values less than maxvalue
496504
);`
497505
assertErrorCode(c, tk, sql7, tmysql.ErrSameNamePartition)
506+
507+
sql8 := "alter table table3 add partition (partition p6);"
508+
assertErrorCode(c, tk, sql8, tmysql.ErrPartitionRequiresValues)
509+
510+
sql9 := "alter table table3 add partition (partition p7 values in (2018));"
511+
assertErrorCode(c, tk, sql9, tmysql.ErrPartitionWrongValues)
512+
513+
sql10 := "alter table table3 add partition partitions 4;"
514+
assertErrorCode(c, tk, sql10, tmysql.ErrPartitionsMustBeDefined)
498515
}
499516

500517
func (s *testIntegrationSuite6) TestAlterTableDropPartition(c *C) {
@@ -800,7 +817,7 @@ func (s *testIntegrationSuite6) TestTruncatePartitionAndDropTable(c *C) {
800817
tk.MustExec("drop table if exists t5;")
801818
tk.MustExec("set @@session.tidb_enable_table_partition=1;")
802819
tk.MustExec(`create table t5(
803-
id int, name varchar(50),
820+
id int, name varchar(50),
804821
purchased date
805822
)
806823
partition by range( year(purchased) ) (
@@ -1456,3 +1473,25 @@ func (s *testIntegrationSuite4) TestPartitionErrorCode(c *C) {
14561473
_, err = tk.Exec("alter table t_part coalesce partition 4;")
14571474
c.Assert(ddl.ErrCoalesceOnlyOnHashPartition.Equal(err), IsTrue)
14581475
}
1476+
1477+
func (s *testIntegrationSuite3) TestUnsupportedPartitionManagementDDLs(c *C) {
1478+
tk := testkit.NewTestKit(c, s.store)
1479+
tk.MustExec("use test;")
1480+
tk.MustExec("drop table if exists test_1465;")
1481+
tk.MustExec(`
1482+
create table test_1465 (a int)
1483+
partition by range(a) (
1484+
partition p1 values less than (10),
1485+
partition p2 values less than (20),
1486+
partition p3 values less than (30)
1487+
);
1488+
`)
1489+
1490+
_, err := tk.Exec("alter table test_1465 truncate partition p1, p2")
1491+
c.Assert(err, ErrorMatches, ".*can't run multi schema change")
1492+
_, err = tk.Exec("alter table test_1465 drop partition p1, p2")
1493+
c.Assert(err, ErrorMatches, ".*can't run multi schema change")
1494+
1495+
_, err = tk.Exec("alter table test_1465 partition by hash(a)")
1496+
c.Assert(err, ErrorMatches, ".*alter table partition is unsupported")
1497+
}

ddl/ddl.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,6 @@ var (
196196

197197
// ErrNotAllowedTypeInPartition returns not allowed type error when creating table partiton with unsupport expression type.
198198
ErrNotAllowedTypeInPartition = terror.ClassDDL.New(codeErrFieldTypeNotAllowedAsPartitionField, mysql.MySQLErrName[mysql.ErrFieldTypeNotAllowedAsPartitionField])
199-
// ErrPartitionsMustBeDefined returns each partition must be defined.
200-
ErrPartitionsMustBeDefined = terror.ClassDDL.New(codePartitionsMustBeDefined, "For RANGE partitions each partition must be defined")
201199
// ErrPartitionMgmtOnNonpartitioned returns it's not a partition table.
202200
ErrPartitionMgmtOnNonpartitioned = terror.ClassDDL.New(codePartitionMgmtOnNonpartitioned, "Partition management on a not partitioned table is not possible")
203201
// ErrDropPartitionNonExistent returns error in list of partition.
@@ -208,14 +206,10 @@ var (
208206
ErrRangeNotIncreasing = terror.ClassDDL.New(codeRangeNotIncreasing, "VALUES LESS THAN value must be strictly increasing for each partition")
209207
// ErrPartitionMaxvalue returns maxvalue can only be used in last partition definition.
210208
ErrPartitionMaxvalue = terror.ClassDDL.New(codePartitionMaxvalue, "MAXVALUE can only be used in last partition definition")
211-
// ErrTooManyValues returns cannot have more than one value for this type of partitioning.
212-
ErrTooManyValues = terror.ClassDDL.New(codeErrTooManyValues, mysql.MySQLErrName[mysql.ErrTooManyValues])
213209
//ErrDropLastPartition returns cannot remove all partitions, use drop table instead.
214210
ErrDropLastPartition = terror.ClassDDL.New(codeDropLastPartition, mysql.MySQLErrName[mysql.ErrDropLastPartition])
215211
//ErrTooManyPartitions returns too many partitions were defined.
216212
ErrTooManyPartitions = terror.ClassDDL.New(codeTooManyPartitions, mysql.MySQLErrName[mysql.ErrTooManyPartitions])
217-
//ErrNoParts returns no partition were defined.
218-
ErrNoParts = terror.ClassDDL.New(codeNoParts, mysql.MySQLErrName[mysql.ErrNoParts])
219213
//ErrPartitionFunctionIsNotAllowed returns this partition function is not allowed.
220214
ErrPartitionFunctionIsNotAllowed = terror.ClassDDL.New(codePartitionFunctionIsNotAllowed, mysql.MySQLErrName[mysql.ErrPartitionFunctionIsNotAllowed])
221215
// ErrPartitionFuncNotAllowed returns partition function returns the wrong type.
@@ -237,8 +231,6 @@ var (
237231
ErrTableCantHandleFt = terror.ClassDDL.New(codeErrTableCantHandleFt, mysql.MySQLErrName[mysql.ErrTableCantHandleFt])
238232
// ErrFieldNotFoundPart returns an error when 'partition by columns' are not found in table columns.
239233
ErrFieldNotFoundPart = terror.ClassDDL.New(codeFieldNotFoundPart, mysql.MySQLErrName[mysql.ErrFieldNotFoundPart])
240-
// ErrPartitionColumnList returns "Inconsistency in usage of column lists for partitioning".
241-
ErrPartitionColumnList = terror.ClassDDL.New(codePartitionColumnList, mysql.MySQLErrName[mysql.ErrPartitionColumnList])
242234
)
243235

244236
// DDL is responsible for updating schema in data store and maintaining in-memory InfoSchema cache.
@@ -754,6 +746,14 @@ const (
754746
codeErrGeneratedColumnRefAutoInc = terror.ErrCode(mysql.ErrGeneratedColumnRefAutoInc)
755747
codeNotSupportedAlterOperation = terror.ErrCode(mysql.ErrAlterOperationNotSupportedReason)
756748
codeFieldNotFoundPart = terror.ErrCode(mysql.ErrFieldNotFoundPart)
749+
codePartitionRequiresValues = terror.ErrCode(mysql.ErrPartitionRequiresValues)
750+
codePartitionWrongNoPart = terror.ErrCode(mysql.ErrPartitionWrongNoPart)
751+
codePartitionWrongNoSubpart = terror.ErrCode(mysql.ErrPartitionWrongNoSubpart)
752+
codePartitionWrongValues = terror.ErrCode(mysql.ErrPartitionWrongValues)
753+
codeRowSinglePartitionField = terror.ErrCode(mysql.ErrRowSinglePartitionField)
754+
codeSubpartition = terror.ErrCode(mysql.ErrSubpartition)
755+
codeSystemVersioningWrongPartitions = terror.ErrCode(mysql.ErrSystemVersioningWrongPartitions)
756+
codeWrongPartitionTypeExpectedSystemTime = terror.ErrCode(mysql.ErrWrongPartitionTypeExpectedSystemTime)
757757
codePartitionColumnList = terror.ErrCode(mysql.ErrPartitionColumnList)
758758
codeOnlyOnRangeListPartition = terror.ErrCode(mysql.ErrOnlyOnRangeListPartition)
759759
)
@@ -818,6 +818,14 @@ func init() {
818818
codePartitionColumnList: mysql.ErrPartitionColumnList,
819819
codeInvalidDefaultValue: mysql.ErrInvalidDefault,
820820
codeErrGeneratedColumnRefAutoInc: mysql.ErrGeneratedColumnRefAutoInc,
821+
codePartitionRequiresValues: mysql.ErrPartitionRequiresValues,
822+
codePartitionWrongNoPart: mysql.ErrPartitionWrongNoPart,
823+
codePartitionWrongNoSubpart: mysql.ErrPartitionWrongNoSubpart,
824+
codePartitionWrongValues: mysql.ErrPartitionWrongValues,
825+
codeRowSinglePartitionField: mysql.ErrRowSinglePartitionField,
826+
codeSubpartition: mysql.ErrSubpartition,
827+
codeSystemVersioningWrongPartitions: mysql.ErrSystemVersioningWrongPartitions,
828+
codeWrongPartitionTypeExpectedSystemTime: mysql.ErrWrongPartitionTypeExpectedSystemTime,
821829
codeOnlyOnRangeListPartition: mysql.ErrOnlyOnRangeListPartition,
822830
}
823831
terror.ErrClassToMySQLCodes[terror.ClassDDL] = ddlMySQLErrCodes

ddl/ddl_api.go

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,12 +1563,12 @@ func checkRangeColumnsPartitionValue(ctx sessionctx.Context, tbInfo *model.Table
15631563
// Range columns partition key supports multiple data types with integer、datetime、string.
15641564
defs := pi.Definitions
15651565
if len(defs) < 1 {
1566-
return errors.Trace(ErrPartitionsMustBeDefined)
1566+
return ast.ErrPartitionsMustBeDefined.GenWithStackByArgs("RANGE")
15671567
}
15681568

15691569
curr := &defs[0]
15701570
if len(curr.LessThan) != len(pi.Columns) {
1571-
return errors.Trace(ErrPartitionColumnList)
1571+
return errors.Trace(ast.ErrPartitionColumnList)
15721572
}
15731573
for i := 1; i < len(defs); i++ {
15741574
prev, curr := curr, &defs[i]
@@ -1585,7 +1585,7 @@ func checkRangeColumnsPartitionValue(ctx sessionctx.Context, tbInfo *model.Table
15851585

15861586
func checkTwoRangeColumns(ctx sessionctx.Context, curr, prev *model.PartitionDefinition, pi *model.PartitionInfo, tbInfo *model.TableInfo) (bool, error) {
15871587
if len(curr.LessThan) != len(pi.Columns) {
1588-
return false, errors.Trace(ErrPartitionColumnList)
1588+
return false, errors.Trace(ast.ErrPartitionColumnList)
15891589
}
15901590
for i := 0; i < len(pi.Columns); i++ {
15911591
// Special handling for MAXVALUE.
@@ -1792,8 +1792,7 @@ func resolveAlterTableSpec(ctx sessionctx.Context, specs []*ast.AlterTableSpec)
17921792
validSpecs = append(validSpecs, spec)
17931793
}
17941794

1795-
if len(validSpecs) != 1 {
1796-
// TODO: Hanlde len(validSpecs) == 0.
1795+
if len(validSpecs) > 1 {
17971796
// Now we only allow one schema changing at the same time.
17981797
return nil, errRunMultiSchemaChanges
17991798
}
@@ -1880,6 +1879,9 @@ func (d *ddl) AlterTable(ctx sessionctx.Context, ident ast.Ident, specs []*ast.A
18801879
err = ErrUnsupportedModifyPrimaryKey.GenWithStackByArgs("drop")
18811880
case ast.AlterTableRenameIndex:
18821881
err = d.RenameIndex(ctx, ident, spec)
1882+
case ast.AlterTablePartition:
1883+
// Prevent silent succeed if user executes ALTER TABLE x PARTITION BY ...
1884+
err = errors.New("alter table partition is unsupported")
18831885
case ast.AlterTableOption:
18841886
for i, opt := range spec.Options {
18851887
switch opt.Tp {
@@ -2104,11 +2106,7 @@ func (d *ddl) AddTablePartitions(ctx sessionctx.Context, ident ast.Ident, spec *
21042106

21052107
meta := t.Meta()
21062108
if meta.GetPartitionInfo() == nil {
2107-
return errors.Trace(ErrPartitionMgmtOnNonpartitioned)
2108-
}
2109-
// We don't support add hash type partition now.
2110-
if meta.Partition.Type == model.PartitionTypeHash {
2111-
return errors.Trace(ErrUnsupportedAddPartition)
2109+
return errors.Trace(ast.ErrPartitionColumnList)
21122110
}
21132111

21142112
partInfo, err := buildPartitionInfo(meta, d, spec)
@@ -2161,20 +2159,28 @@ func (d *ddl) CoalescePartitions(ctx sessionctx.Context, ident ast.Ident, spec *
21612159
return errors.Trace(ErrPartitionMgmtOnNonpartitioned)
21622160
}
21632161

2164-
// Coalesce partition can only be used on hash/key partitions.
2165-
if meta.Partition.Type == model.PartitionTypeRange {
2166-
return errors.Trace(ErrCoalesceOnlyOnHashPartition)
2167-
}
2168-
2162+
switch meta.Partition.Type {
21692163
// We don't support coalesce partitions hash type partition now.
2170-
if meta.Partition.Type == model.PartitionTypeHash {
2164+
case model.PartitionTypeHash:
21712165
return errors.Trace(ErrUnsupportedCoalescePartition)
2166+
2167+
// Key type partition cannot be constructed currently, ignoring it for now.
2168+
case model.PartitionTypeKey:
2169+
2170+
// Coalesce partition can only be used on hash/key partitions.
2171+
default:
2172+
return errors.Trace(ErrCoalesceOnlyOnHashPartition)
21722173
}
21732174

21742175
return errors.Trace(err)
21752176
}
21762177

21772178
func (d *ddl) TruncateTablePartition(ctx sessionctx.Context, ident ast.Ident, spec *ast.AlterTableSpec) error {
2179+
// TODO: Support truncate multiple partitions
2180+
if len(spec.PartitionNames) != 1 {
2181+
return errRunMultiSchemaChanges
2182+
}
2183+
21782184
is := d.infoHandle.Get()
21792185
schema, ok := is.SchemaByName(ident.Schema)
21802186
if !ok {
@@ -2190,7 +2196,7 @@ func (d *ddl) TruncateTablePartition(ctx sessionctx.Context, ident ast.Ident, sp
21902196
}
21912197

21922198
var pid int64
2193-
pid, err = tables.FindPartitionByName(meta, spec.Name)
2199+
pid, err = tables.FindPartitionByName(meta, spec.PartitionNames[0].L)
21942200
if err != nil {
21952201
return errors.Trace(err)
21962202
}
@@ -2212,6 +2218,11 @@ func (d *ddl) TruncateTablePartition(ctx sessionctx.Context, ident ast.Ident, sp
22122218
}
22132219

22142220
func (d *ddl) DropTablePartition(ctx sessionctx.Context, ident ast.Ident, spec *ast.AlterTableSpec) error {
2221+
// TODO: Support drop multiple partitions
2222+
if len(spec.PartitionNames) != 1 {
2223+
return errRunMultiSchemaChanges
2224+
}
2225+
22152226
is := d.infoHandle.Get()
22162227
schema, ok := is.SchemaByName(ident.Schema)
22172228
if !ok {
@@ -2225,7 +2236,8 @@ func (d *ddl) DropTablePartition(ctx sessionctx.Context, ident ast.Ident, spec *
22252236
if meta.GetPartitionInfo() == nil {
22262237
return errors.Trace(ErrPartitionMgmtOnNonpartitioned)
22272238
}
2228-
err = checkDropTablePartition(meta, spec.Name)
2239+
partName := spec.PartitionNames[0].L
2240+
err = checkDropTablePartition(meta, partName)
22292241
if err != nil {
22302242
return errors.Trace(err)
22312243
}
@@ -2235,7 +2247,7 @@ func (d *ddl) DropTablePartition(ctx sessionctx.Context, ident ast.Ident, spec *
22352247
TableID: meta.ID,
22362248
Type: model.ActionDropTablePartition,
22372249
BinlogInfo: &model.HistoryInfo{},
2238-
Args: []interface{}{spec.Name},
2250+
Args: []interface{}{partName},
22392251
}
22402252

22412253
err = d.doDDLJob(ctx, job)
@@ -3219,9 +3231,15 @@ func validateCommentLength(vars *variable.SessionVars, comment string, maxLen in
32193231
}
32203232

32213233
func buildPartitionInfo(meta *model.TableInfo, d *ddl, spec *ast.AlterTableSpec) (*model.PartitionInfo, error) {
3222-
if meta.Partition.Type == model.PartitionTypeRange && len(spec.PartDefinitions) == 0 {
3223-
return nil, errors.Trace(ErrPartitionsMustBeDefined)
3234+
if meta.Partition.Type == model.PartitionTypeRange {
3235+
if len(spec.PartDefinitions) == 0 {
3236+
return nil, ast.ErrPartitionsMustBeDefined.GenWithStackByArgs(meta.Partition.Type)
3237+
}
3238+
} else {
3239+
// we don't support ADD PARTITION for all other partition types yet.
3240+
return nil, errors.Trace(ErrUnsupportedAddPartition)
32243241
}
3242+
32253243
part := &model.PartitionInfo{
32263244
Type: meta.Partition.Type,
32273245
Expr: meta.Partition.Expr,
@@ -3234,7 +3252,12 @@ func buildPartitionInfo(meta *model.TableInfo, d *ddl, spec *ast.AlterTableSpec)
32343252
}
32353253
buf := new(bytes.Buffer)
32363254
for ith, def := range spec.PartDefinitions {
3237-
for _, expr := range def.LessThan {
3255+
if err := def.Clause.Validate(part.Type, len(part.Columns)); err != nil {
3256+
return nil, errors.Trace(err)
3257+
}
3258+
// For RANGE partition only VALUES LESS THAN should be possible.
3259+
clause := def.Clause.(*ast.PartitionDefinitionClauseLessThan)
3260+
for _, expr := range clause.Exprs {
32383261
tp := expr.GetType().Tp
32393262
if len(part.Columns) == 0 {
32403263
// Partition by range.
@@ -3249,14 +3272,15 @@ func buildPartitionInfo(meta *model.TableInfo, d *ddl, spec *ast.AlterTableSpec)
32493272
}
32503273
// Partition by range columns if len(part.Columns) != 0.
32513274
}
3275+
comment, _ := def.Comment()
32523276
piDef := model.PartitionDefinition{
32533277
Name: def.Name,
32543278
ID: genIDs[ith],
3255-
Comment: def.Comment,
3279+
Comment: comment,
32563280
}
32573281

32583282
buf := new(bytes.Buffer)
3259-
for _, expr := range def.LessThan {
3283+
for _, expr := range clause.Exprs {
32603284
expr.Format(buf)
32613285
piDef.LessThan = append(piDef.LessThan, buf.String())
32623286
buf.Reset()

0 commit comments

Comments
 (0)