From 25ee53a7a48f50db38bc1f1efc2655697dceb9ce Mon Sep 17 00:00:00 2001 From: jwxiong Date: Fri, 19 Mar 2021 13:47:43 +0800 Subject: [PATCH 1/4] add test --- ddl/db_partition_test.go | 17 ++++++++++++++++- ddl/error.go | 2 ++ ddl/partition.go | 29 +++++++++++++++++------------ 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/ddl/db_partition_test.go b/ddl/db_partition_test.go index 2b44bf2c8cec8..6481fd9d8fe11 100644 --- a/ddl/db_partition_test.go +++ b/ddl/db_partition_test.go @@ -530,7 +530,19 @@ create table log_message_1 ( }, { "create table t1 (a bigint unsigned) partition by list (a) (partition p0 values in (10, 20, 30, -1));", - ddl.ErrWrongTypeColumnValue, + ddl.ErrPartitionConstDomain, + }, + { + "create table t1 (a bigint unsigned) partition by range (a) (partition p0 values less than (-1));", + ddl.ErrPartitionConstDomain, + }, + { + "create table t1 (a int unsigned) partition by range (a) (partition p0 values less than (-1));", + ddl.ErrPartitionConstDomain, + }, + { + "create table t1 (a tinyint(20) unsigned) partition by range (a) (partition p0 values less than (-1));", + ddl.ErrPartitionConstDomain, }, { "CREATE TABLE new (a TIMESTAMP NOT NULL PRIMARY KEY) PARTITION BY RANGE (a % 2) (PARTITION p VALUES LESS THAN (20080819));", @@ -568,6 +580,9 @@ create table log_message_1 ( tk.MustExec(`create table t(a int) partition by range columns (a) ( partition p0 values less than (10), partition p1 values less than (20));`) + + tk.MustExec("drop table if exists t;") + tk.MustExec(`create table t(a int) partition by range (a) (partition p0 values less than (18446744073709551615));`) } func (s *testIntegrationSuite1) TestDisableTablePartition(c *C) { diff --git a/ddl/error.go b/ddl/error.go index 9a91794034798..3a19a4c8ce5e5 100644 --- a/ddl/error.go +++ b/ddl/error.go @@ -176,6 +176,8 @@ var ( ErrDropLastPartition = dbterror.ClassDDL.NewStd(mysql.ErrDropLastPartition) // ErrTooManyPartitions returns too many partitions were defined. ErrTooManyPartitions = dbterror.ClassDDL.NewStd(mysql.ErrTooManyPartitions) + // ErrPartitionConstDomain returns partition constant is out of partition function domain + ErrPartitionConstDomain = dbterror.ClassDDL.NewStd(mysql.ErrPartitionConstDomain) // ErrPartitionFunctionIsNotAllowed returns this partition function is not allowed. ErrPartitionFunctionIsNotAllowed = dbterror.ClassDDL.NewStd(mysql.ErrPartitionFunctionIsNotAllowed) // ErrPartitionFuncNotAllowed returns partition function returns the wrong type. diff --git a/ddl/partition.go b/ddl/partition.go index 3daf3322f959d..eff89f1ba24ee 100644 --- a/ddl/partition.go +++ b/ddl/partition.go @@ -493,7 +493,7 @@ func buildRangePartitionDefinitions(ctx sessionctx.Context, defs []*ast.Partitio func checkPartitionValuesIsInt(ctx sessionctx.Context, def *ast.PartitionDefinition, exprs []ast.ExprNode, tbInfo *model.TableInfo) error { tp := types.NewFieldType(mysql.TypeLonglong) - if isRangePartitionColUnsignedBigint(tbInfo.Columns, tbInfo.Partition) { + if isColUnsigned(tbInfo.Columns, tbInfo.Partition) { tp.Flag |= mysql.UnsignedFlag } for _, exp := range exprs { @@ -505,12 +505,17 @@ func checkPartitionValuesIsInt(ctx sessionctx.Context, def *ast.PartitionDefinit return err } switch val.Kind() { - case types.KindInt64, types.KindUint64, types.KindNull: + case types.KindUint64, types.KindNull: + case types.KindInt64: + if mysql.HasUnsignedFlag(tp.Flag) && val.GetInt64() < 0 { + return ErrPartitionConstDomain.GenWithStackByArgs() + } default: return ErrValuesIsNotIntType.GenWithStackByArgs(def.Name) } + _, err = val.ConvertTo(ctx.GetSessionVars().StmtCtx, tp) - if err != nil { + if err != nil && !types.ErrOverflow.Equal(err) { return ErrWrongTypeColumnValue.GenWithStackByArgs() } } @@ -644,14 +649,14 @@ func checkRangePartitionValue(ctx sessionctx.Context, tblInfo *model.TableInfo) if strings.EqualFold(defs[len(defs)-1].LessThan[0], partitionMaxValue) { defs = defs[:len(defs)-1] } - isUnsignedBigint := isRangePartitionColUnsignedBigint(cols, pi) + isUnsigned := isColUnsigned(cols, pi) var prevRangeValue interface{} for i := 0; i < len(defs); i++ { if strings.EqualFold(defs[i].LessThan[0], partitionMaxValue) { return errors.Trace(ErrPartitionMaxvalue) } - currentRangeValue, fromExpr, err := getRangeValue(ctx, defs[i].LessThan[0], isUnsignedBigint) + currentRangeValue, fromExpr, err := getRangeValue(ctx, defs[i].LessThan[0], isUnsigned) if err != nil { return errors.Trace(err) } @@ -665,7 +670,7 @@ func checkRangePartitionValue(ctx sessionctx.Context, tblInfo *model.TableInfo) continue } - if isUnsignedBigint { + if isUnsigned { if currentRangeValue.(uint64) <= prevRangeValue.(uint64) { return errors.Trace(ErrRangeNotIncreasing) } @@ -707,7 +712,7 @@ func formatListPartitionValue(ctx sessionctx.Context, tblInfo *model.TableInfo) cols := make([]*model.ColumnInfo, 0, len(pi.Columns)) if len(pi.Columns) == 0 { tp := types.NewFieldType(mysql.TypeLonglong) - if isRangePartitionColUnsignedBigint(tblInfo.Columns, tblInfo.Partition) { + if isColUnsigned(tblInfo.Columns, tblInfo.Partition) { tp.Flag |= mysql.UnsignedFlag } colTps = []*types.FieldType{tp} @@ -758,9 +763,9 @@ func formatListPartitionValue(ctx sessionctx.Context, tblInfo *model.TableInfo) // getRangeValue gets an integer from the range value string. // The returned boolean value indicates whether the input string is a constant expression. -func getRangeValue(ctx sessionctx.Context, str string, unsignedBigint bool) (interface{}, bool, error) { +func getRangeValue(ctx sessionctx.Context, str string, unsigned bool) (interface{}, bool, error) { // Unsigned bigint was converted to uint64 handle. - if unsignedBigint { + if unsigned { if value, err := strconv.ParseUint(str, 10, 64); err == nil { return value, false, nil } @@ -1649,10 +1654,10 @@ func (cns columnNameSlice) At(i int) string { return cns[i].Name.L } -// isRangePartitionColUnsignedBigint returns true if the partitioning key column type is unsigned bigint type. -func isRangePartitionColUnsignedBigint(cols []*model.ColumnInfo, pi *model.PartitionInfo) bool { +// isColUnsigned returns true if the partitioning key column type is unsigned bigint type. +func isColUnsigned(cols []*model.ColumnInfo, pi *model.PartitionInfo) bool { for _, col := range cols { - isUnsigned := col.Tp == mysql.TypeLonglong && mysql.HasUnsignedFlag(col.Flag) + isUnsigned := mysql.HasUnsignedFlag(col.Flag) if isUnsigned && strings.Contains(strings.ToLower(pi.Expr), col.Name.L) { return true } From d2c1e7036e7e65a3174870bb9b0d1b2c9c8730a6 Mon Sep 17 00:00:00 2001 From: jwxiong Date: Fri, 19 Mar 2021 14:59:06 +0800 Subject: [PATCH 2/4] generate errors.toml --- errors.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/errors.toml b/errors.toml index 0b5f0397890db..7b75f56e74f09 100644 --- a/errors.toml +++ b/errors.toml @@ -261,6 +261,11 @@ error = ''' Duplicate partition name %-.192s ''' +["ddl:1563"] +error = ''' +Partition constant is out of partition function domain +''' + ["ddl:1564"] error = ''' This partition function is not allowed From b0176e6b101ac24a34beb2e1832faa86141ebd29 Mon Sep 17 00:00:00 2001 From: xiongjiwei Date: Tue, 23 Mar 2021 14:10:56 +0800 Subject: [PATCH 3/4] Update ddl/partition.go Co-authored-by: tangenta --- ddl/partition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddl/partition.go b/ddl/partition.go index eff89f1ba24ee..56e4b505b471d 100644 --- a/ddl/partition.go +++ b/ddl/partition.go @@ -1654,7 +1654,7 @@ func (cns columnNameSlice) At(i int) string { return cns[i].Name.L } -// isColUnsigned returns true if the partitioning key column type is unsigned bigint type. +// isColUnsigned returns true if the partitioning key column is unsigned. func isColUnsigned(cols []*model.ColumnInfo, pi *model.PartitionInfo) bool { for _, col := range cols { isUnsigned := mysql.HasUnsignedFlag(col.Flag) From 3e4a07ad6168dbef3b642b7d0370f6d25c646795 Mon Sep 17 00:00:00 2001 From: xiongjiwei Date: Tue, 23 Mar 2021 14:12:28 +0800 Subject: [PATCH 4/4] Update ddl/error.go Co-authored-by: tangenta --- ddl/error.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddl/error.go b/ddl/error.go index 3a19a4c8ce5e5..852d2218c6275 100644 --- a/ddl/error.go +++ b/ddl/error.go @@ -176,7 +176,7 @@ var ( ErrDropLastPartition = dbterror.ClassDDL.NewStd(mysql.ErrDropLastPartition) // ErrTooManyPartitions returns too many partitions were defined. ErrTooManyPartitions = dbterror.ClassDDL.NewStd(mysql.ErrTooManyPartitions) - // ErrPartitionConstDomain returns partition constant is out of partition function domain + // ErrPartitionConstDomain returns partition constant is out of partition function domain. ErrPartitionConstDomain = dbterror.ClassDDL.NewStd(mysql.ErrPartitionConstDomain) // ErrPartitionFunctionIsNotAllowed returns this partition function is not allowed. ErrPartitionFunctionIsNotAllowed = dbterror.ClassDDL.NewStd(mysql.ErrPartitionFunctionIsNotAllowed)