From bf01def757ef89bec01131eb8fb220fcb7169bec Mon Sep 17 00:00:00 2001 From: Lingyu Song Date: Tue, 14 Jan 2020 17:09:56 +0800 Subject: [PATCH] ddl: avoid panic when creating partition table with unsupported expression (#14295) --- ddl/ddl_api.go | 33 +++++++++++++++++++-------------- ddl/partition.go | 26 ++++++++++++++++++++++---- table/tables/partition_test.go | 14 ++++++++++++++ 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index c30b55cddc..3d9d44d224 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -1384,25 +1384,30 @@ func buildTableInfoWithCheck(ctx sessionctx.Context, s *ast.CreateTableStmt, dbC return nil, errors.Trace(err) } - pi, err := buildTablePartitionInfo(ctx, s) - if err != nil { - return nil, errors.Trace(err) - } - - if pi != nil { - switch pi.Type { - case model.PartitionTypeRange: - err = checkPartitionByRange(ctx, tbInfo, pi, cols, s) - case model.PartitionTypeHash: - err = checkPartitionByHash(ctx, pi, s, cols, tbInfo) - } + if s.Partition != nil { + err := checkPartitionExprValid(ctx, tbInfo, s.Partition.Expr) if err != nil { return nil, errors.Trace(err) } - if err = checkRangePartitioningKeysConstraints(ctx, s, tbInfo, newConstraints); err != nil { + pi, err := buildTablePartitionInfo(ctx, s) + if err != nil { return nil, errors.Trace(err) } - tbInfo.Partition = pi + if pi != nil { + switch pi.Type { + case model.PartitionTypeRange: + err = checkPartitionByRange(ctx, tbInfo, pi, cols, s) + case model.PartitionTypeHash: + err = checkPartitionByHash(ctx, pi, s, cols, tbInfo) + } + if err != nil { + return nil, errors.Trace(err) + } + if err = checkRangePartitioningKeysConstraints(ctx, s, tbInfo, newConstraints); err != nil { + return nil, errors.Trace(err) + } + tbInfo.Partition = pi + } } if err = handleTableOptions(s.Options, tbInfo); err != nil { diff --git a/ddl/partition.go b/ddl/partition.go index b4362c8059..be0d1b4166 100644 --- a/ddl/partition.go +++ b/ddl/partition.go @@ -294,10 +294,10 @@ func defaultTimezoneDependent(ctx sessionctx.Context, tblInfo *model.TableInfo, return !v, nil } -// checkPartitionFuncValid checks partition function validly. -func checkPartitionFuncValid(ctx sessionctx.Context, tblInfo *model.TableInfo, expr ast.ExprNode) error { +// checkPartitionExprValid checks partition expression validly. +func checkPartitionExprValid(ctx sessionctx.Context, tblInfo *model.TableInfo, expr ast.ExprNode) error { switch v := expr.(type) { - case *ast.FuncCastExpr, *ast.CaseExpr: + case *ast.FuncCastExpr, *ast.CaseExpr, *ast.SubqueryExpr, *ast.WindowFuncExpr, *ast.RowExpr, *ast.DefaultExpr, *ast.ValuesExpr: return errors.Trace(ErrPartitionFunctionIsNotAllowed) case *ast.FuncCallExpr: // check function which allowed in partitioning expressions @@ -326,17 +326,35 @@ func checkPartitionFuncValid(ctx sessionctx.Context, tblInfo *model.TableInfo, e switch v.Op { case opcode.Or, opcode.And, opcode.Xor, opcode.LeftShift, opcode.RightShift, opcode.BitNeg, opcode.Div: return errors.Trace(ErrPartitionFunctionIsNotAllowed) + default: + if err := checkPartitionExprValid(ctx, tblInfo, v.L); err != nil { + return errors.Trace(err) + } + if err := checkPartitionExprValid(ctx, tblInfo, v.R); err != nil { + return errors.Trace(err) + } } return nil case *ast.UnaryOperationExpr: if v.Op == opcode.BitNeg { return errors.Trace(ErrPartitionFunctionIsNotAllowed) } + if err := checkPartitionExprValid(ctx, tblInfo, v.V); err != nil { + return errors.Trace(err) + } return nil } + return nil +} +// checkPartitionFuncValid checks partition function validly. +func checkPartitionFuncValid(ctx sessionctx.Context, tblInfo *model.TableInfo, expr ast.ExprNode) error { + err := checkPartitionExprValid(ctx, tblInfo, expr) + if err != nil { + return err + } // check constant. - _, err := checkPartitionColumns(tblInfo, expr) + _, err = checkPartitionColumns(tblInfo, expr) return err } diff --git a/table/tables/partition_test.go b/table/tables/partition_test.go index 39cbcde56d..3e94c59a53 100644 --- a/table/tables/partition_test.go +++ b/table/tables/partition_test.go @@ -18,6 +18,7 @@ import ( . "github.com/pingcap/check" "github.com/pingcap/parser/model" + "github.com/pingcap/tidb/ddl" "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/sessionctx" @@ -306,3 +307,16 @@ func (ts *testSuite) TestLocateRangePartitionErr(c *C) { _, err := tk.Exec("INSERT INTO t_month_data_monitor VALUES (4, '2019-04-04')") c.Assert(table.ErrNoPartitionForGivenValue.Equal(err), IsTrue) } + +func (ts *testSuite) TestCreatePartitionTableNotSupport(c *C) { + tk := testkit.NewTestKitWithInit(c, ts.store) + tk.MustExec("use test") + _, err := tk.Exec(`create table t7 (a int) partition by range (mod((select * from t), 5)) (partition p1 values less than (1));`) + c.Assert(ddl.ErrPartitionFunctionIsNotAllowed.Equal(err), IsTrue) + _, err = tk.Exec(`create table t7 (a int) partition by range (1 + (select * from t)) (partition p1 values less than (1));`) + c.Assert(ddl.ErrPartitionFunctionIsNotAllowed.Equal(err), IsTrue) + _, err = tk.Exec(`create table t7 (a int) partition by range (a + row(1, 2, 3)) (partition p1 values less than (1));`) + c.Assert(ddl.ErrPartitionFunctionIsNotAllowed.Equal(err), IsTrue) + _, err = tk.Exec(`create table t7 (a int) partition by range (-(select * from t)) (partition p1 values less than (1));`) + c.Assert(ddl.ErrPartitionFunctionIsNotAllowed.Equal(err), IsTrue) +}