ddl: avoid panic when creating partition table with unsupported expression (#14295)
This commit is contained in:
@ -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 {
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user