ddl: avoid panic when creating partition table with unsupported expression (#14295)

This commit is contained in:
Lingyu Song
2020-01-14 17:09:56 +08:00
committed by tiancaiamao
parent 562a448b7d
commit bf01def757
3 changed files with 55 additions and 18 deletions

View File

@ -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 {

View File

@ -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
}

View File

@ -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)
}